Microcontroller Programming Types: Graphical Tools, C/C++, Python, and IDEs Explained

This post contains affiliate links, marked with *. As an Amazon Associate I earn from qualifying purchases, at no extra cost to you. It helps keep the tutorials free.

Quick summary

Overview of the ways to program a microcontroller: block-based tools (Scratch, Blockly, mBlock), assembly, C/C++, MicroPython/CircuitPython and JavaScript, and the IDEs used to write and upload the code (Arduino IDE, PlatformIO, Thonny, STM32CubeIDE). Includes a comparison table, a use-case guide and an LED blink example in C++, MicroPython and blocks.

A microcontroller controls the anti-lock brakes (ABS) in a car, a wall thermostat or a hobby robot. My first board was an Arduino Uno, and my first project with it controlled a DC (direct current) motor. How you program such a chip decides how quickly you learn and how much control you get over the hardware. No microcontroller programming type is best for every project. The use-case guide below helps you choose.

What is microcontroller programming?

A microcontroller is a small computer on a single integrated circuit. It has a processor (CPU), memory (RAM and flash) and peripherals (built-in hardware blocks such as timers, analog-to-digital converters and serial interfaces) on one chip. Examples are the ATmega328P on the Arduino Uno R3, the ESP32 used for Wi-Fi and Bluetooth projects, and the RP2040 inside the Raspberry Pi Pico. The Pico is a microcontroller board; the larger Raspberry Pi is a computer that runs Linux.

Microcontroller programming means writing the instructions that the chip’s processor runs: read a sensor, drive a motor, send data to another device. Unlike desktop software, the code usually runs in an endless loop without an operating system. The programmer is responsible for timing, memory use and every hardware detail.

There are four main approaches:

  • Block-based (graphical) programming: you assemble the program from visual blocks.
  • Assembly: you write the processor’s own instructions.
  • Compiled languages (C/C++): you write readable code that a compiler translates into machine instructions before upload.
  • Interpreted languages (MicroPython, CircuitPython, JavaScript): the code is read and executed on the chip while the program runs.

The IDE (Integrated Development Environment) is a separate tool: the program you use to write, compile and upload code in any of these languages.

Block-based programming

Block-based programming replaces typed code with blocks that you drag and drop. Each block stands for a loop, a condition, a variable or a hardware command, and you connect the blocks to build the program. Blocks make the program flow visible and rule out syntax errors. These tools are made for school students, teachers and people who have never written code. They teach loops, conditions, functions and variables without typed syntax, which makes the later step to C/C++ or MicroPython smaller. Scratch and many other block editors can be switched to other languages, which helps learners who do not read English well.

Scratch editor with drag-and-drop blocks for a simple program

Popular block-based tools

  • Scratch, developed by the MIT Media Lab, is a block-based environment aimed at animations and games on a computer. S4A (Scratch for Arduino) is a modified version of Scratch. You upload a small program (firmware) to the Arduino once; after that, the board stays connected by USB and the PC runs your blocks.
  • Blockly, created by Google, is an open-source library that powers the block editors of many educational platforms. It generates real code in JavaScript, Python, Lua or other languages. Many Blockly-based editors show the generated code next to the blocks, which makes the step from blocks to typed code easier.
  • mBlock lets you build a program for Arduino boards from blocks and upload it directly. Tinkercad Circuits has a Code Blocks mode that runs the program in a browser simulation and shows the matching Arduino code.

I use blocks myself on the phone side of my projects. The Android apps that send Bluetooth commands to my Arduino robots are built in MIT App Inventor, whose blocks editor is based on Blockly.

Limitations

As a program grows, dozens of nested blocks make the workspace hard to read. Blocks also give no direct access to registers (small memory cells inside the chip whose bits switch peripherals on and off and set their mode), to memory or to exact timing. Most learners move on to C/C++ or MicroPython once they know the basics.

Assembly

What assembly is and why it gives full control

Assembly is a low-level language that maps almost directly to the machine instructions the processor runs. Instead of binary ones and zeros, you write short mnemonics such as MOV, ADD and JMP, and the assembler translates them into machine code. Each instruction matches one CPU operation, so you control what the hardware does on every clock cycle (one tick of the chip’s clock; the Uno R3’s 16 MHz clock ticks 16 million times per second).

Because there is no abstraction layer (code that hides hardware details behind simpler commands) between your code and the hardware, assembly lets you decide how every CPU cycle and every byte of memory is used. You can set individual CPU registers, configure peripherals bit by bit and write timing routines that are accurate to one clock cycle. This matters in tight signal-processing loops that need deterministic timing: the code takes exactly the same number of clock cycles on every run. It also matters on chips with only a few kilobytes of RAM.

Where it is still used and why it is hard

Assembly is still used in:

  • Bootloaders: the small program that runs after reset and can load new firmware.
  • Interrupt service routines (ISRs) that must finish in a fixed number of cycles. An ISR is a function the CPU jumps to when a hardware event occurs.
  • Startup code: the first instructions after reset, which prepare the memory before the main program starts.

Many embedded C projects also contain a few lines of inline assembly (assembly instructions written inside the C code) for time-critical work. Assembly code is long: a task that takes one line in Python can take dozens of lines in assembly. The code is architecture-specific: a routine written for an AVR chip (Arduino Uno R3) will not run on an ARM chip (STM32) without a full rewrite. Debugging takes longer, and assembly code written by someone else is hard to read. Still, reading a little assembly shows you what the compiler turns your C code into.

Compiled languages: C and C++

High-level languages hide the registers and memory addresses behind variables with descriptive names, loops, functions and libraries. A compiler translates the code into machine instructions before upload; an interpreter reads and executes it on the chip while the program runs. C and C++ code is faster to write than assembly and easier to read, and it runs on other chips after a recompile.

Program code on a screen

C and C++ dominate embedded development. Arduino code is C++ plus the Arduino framework, a set of functions such as digitalWrite() and delay() that hide the register-level setup. That is why most Arduino tutorials are written in C++. C gives low-level access to hardware through pointers (variables that hold a memory address) and direct register access, and it still has structured features such as functions and data types. C++ adds classes (data and the functions that work on it, bundled together) and templates (code that works for several data types), which help organize larger projects. C/C++ is the default language for production embedded systems, because it runs fast, gives direct hardware control and has compilers for a wide range of chips. If you have followed my servo control with joystick and OLED display tutorial, you have already written C++.

I reached the limit of a plain loop() (the Arduino function that repeats forever) on my OmArm One robot arm. The web server and the servo updates shared loop(), and while I dragged a slider in the web app, the time between two servo updates jumped between 4 and 30 ms. The arm moved in uneven steps. The fix was a separate task under FreeRTOS, the real-time operating system (RTOS) that comes with the Arduino framework for the ESP32. An RTOS is a small operating system that switches between several tasks with fixed timing. FreeRTOS now runs the servo update every 4 ms, with a higher priority than the web server.

Interpreted languages: MicroPython, CircuitPython and JavaScript

MicroPython and CircuitPython are lean versions of Python 3 that run directly on microcontrollers such as the ESP32, the RP2040 and Microchip’s ARM-based SAMD chips. You type commands into a live REPL (Read-Eval-Print Loop) connected to the board and see the result at once. You do not compile anything on the PC. MicroPython on the board translates each line into bytecode (a compact intermediate code) and runs it immediately. This makes MicroPython well suited to prototyping. MicroPython runs noticeably slower than compiled C/C++ and needs more RAM, which matters on small chips.

On microcontrollers, JavaScript is used mainly for IoT (Internet of Things) devices, which exchange data over a network. It runs directly on Espruino boards. Johnny-Five works differently: it runs in Node.js (a program that runs JavaScript on a computer) on a PC or Raspberry Pi. It controls an Arduino over USB through Firmata (a firmware that lets the computer read and switch the board’s pins). JavaScript is event-driven: the code reacts to events such as a button press or an incoming network message instead of checking for them in a loop. That suits devices that spend most of their time waiting. Lua, another small scripting language, runs on the NodeMCU firmware for ESP8266 (the older, Wi-Fi-only predecessor of the ESP32) and ESP32 boards. Both are far less common on microcontrollers than C/C++ or MicroPython. They make sense mainly if you already know the language, for example JavaScript from web development.

IDEs: the tools you write code in

Language, compiler and IDE

Beginners often mix up three terms:

  • A programming language (C++, Python) defines the syntax and rules for writing code.
  • A compiler or interpreter turns that code into something the chip can run.
  • An IDE is the program you work in. It combines a code editor, the compiler or interpreter, upload tools and a serial monitor (a window that shows the text the board sends over USB). Many IDEs also include a debugger, a tool that pauses the running program so you can inspect variables.

You can use the same language in different IDEs, and many IDEs support more than one language.

Arduino IDE editor with C++ code open

Arduino IDE

The Arduino IDE is Arduino’s official development environment, and an Arduino program is called a sketch. The IDE supports C and C++, uploads with one click, includes a serial monitor and installs libraries through the built-in Library Manager. Version 2.x added auto-completion and a debugger. The debugger only works with boards that support hardware debugging, such as the Arduino Zero; the Uno R3 does not. Many of my tutorials, for example the IR remote with LED and servo door, use the Arduino IDE. For a first complete Arduino project, see my line following robot for beginners.

PlatformIO

PlatformIO is an open-source extension for Visual Studio Code, Microsoft’s free code editor. It supports hundreds of boards (Arduino, ESP32, STM32 and more). It adds unit testing (small test programs that check single functions automatically) and static code analysis (a tool that scans the code for bugs without running it). It also installs the libraries and the toolchain (the compiler and upload tools for your board) automatically. PlatformIO is useful once a project has several source files, needs fixed library versions (the same version on every computer) or targets more than one board. You keep writing the same C/C++ code.

Thonny

Thonny is a small Python IDE with built-in MicroPython support. It detects a connected board, opens the REPL, uploads scripts and manages the files on the board. For ESP32 or Raspberry Pi Pico projects in MicroPython, it is usually the quickest way to start.

Professional IDEs

In commercial embedded development, engineers often use the chip vendor’s IDE: STM32CubeIDE (STM32), MPLAB X (Microchip PIC and dsPIC) or Keil MDK (ARM Cortex-M). They offer hardware breakpoints (the chip stops at a chosen line of code), live variable views, views of the peripheral registers and RTOS-aware debugging, which shows each RTOS task and its state. For hobby projects, the Arduino IDE or PlatformIO is enough.

Microcontroller programming types compared

ApproachDifficultyHardware controlExecution speedRAM useReadabilityBest forTypical platforms
Block-based (Scratch, Blockly, mBlock)Very easyLimitedDepends on toolDepends on toolHigh for small programsEducation, first programsArduino (via S4A, Blockly), micro:bit
AssemblyVery hardMaximumFastestLowestLowTime-critical routines, bootloadersAVR, PIC, ARM (architecture-specific)
C / Embedded CModerateHighVery fastLowModerateProduction firmware, Arduino projectsArduino, ESP32, STM32, PIC
C++Moderate to hardHighVery fastLowModerateLarger projects, class-based designArduino, ESP32, STM32
MicroPython / CircuitPythonEasyModerateSlower (interpreted)HighVery highPrototyping, education, IoTESP32, RP2040, SAMD boards
JavaScript (Espruino)Easy to moderateModerateSlowerHighHighIoT, web-connected devicesEspruino boards, ESP8266

Scale: difficulty from very easy to very hard; hardware control from limited to maximum; speed from slower to fastest; RAM use from lowest to high.

Which approach for which project

  • Absolute beginners: an Arduino Uno R3, the Arduino IDE and the Blink sketch in C++ (the standard first program, which makes an LED blink). Block tools such as Scratch or mBlock are an alternative for children and for classes that have never seen code.
  • Robotics: C/C++ in the Arduino IDE or PlatformIO. Servo and motor control need fixed timing, and sensor fusion needs fast calculations. Sensor fusion means combining the readings of several sensors, for example the accelerometer and gyroscope of an IMU (inertial measurement unit). Compiled C/C++ on the microcontroller handles both. In my OmArm robot arms, C++ firmware on the ESP32 drives the servos. On the PC, ROS 2 (Robot Operating System 2, a collection of libraries and tools for robot software) plans the motion, with my code in Python and C++. For a project that combines DC motors, servos and Bluetooth, see my OmObiArm mobile robot arm.
  • Performance-critical embedded systems: Embedded C or C++ with the chip vendor’s IDE and compiler (STM32CubeIDE, MPLAB X, Keil MDK) gives close control over memory and timing and adds hardware debugging. Add inline assembly only where a routine must be cycle-accurate.
  • Fast prototyping and IoT: MicroPython on an ESP32 or Raspberry Pi Pico. You write readable code, test it in the REPL and change it in seconds.

Practical examples

Each example blinks an LED, so you can compare the syntax directly.

Arduino (C/C++): blink an LED

// Arduino C/C++ -- Blink the built-in LED
void setup() {
  pinMode(LED_BUILTIN, OUTPUT);  // Set LED pin as output
}

void loop() {
  digitalWrite(LED_BUILTIN, HIGH);  // Turn LED on
  delay(1000);                      // Wait one second
  digitalWrite(LED_BUILTIN, LOW);   // Turn LED off
  delay(1000);                      // Wait one second
}

LED_BUILTIN is a predefined constant for the board’s built-in LED (pin 13 on the Uno), and delay() takes milliseconds, so delay(1000) waits one second. setup() runs once after power-on or reset, then loop() repeats forever. The Arduino framework does the hardware initialization for you.

ESP32 with MicroPython: blink an LED

# MicroPython on ESP32 -- Blink an LED on GPIO 2
from machine import Pin
from time import sleep

led = Pin(2, Pin.OUT)

while True:
    led.value(1)   # Turn LED on
    sleep(1)        # Wait one second
    led.value(0)   # Turn LED off
    sleep(1)        # Wait one second

MicroPython has no setup()/loop() pair: code at the top runs once, and the while True loop repeats forever. The machine module controls the GPIO pins (general-purpose input/output). sleep() takes seconds, while Arduino’s delay() takes milliseconds. GPIO 2 drives the built-in LED on many ESP32 DevKit boards; check the pinout of your board. You can also type these lines one by one into the Thonny REPL and watch each command take effect.

The same program in blocks

In a block editor, the blink program is a “forever” block that contains four blocks: set pin 13 HIGH, wait 1 second, set pin 13 LOW, wait 1 second. Tools such as mBlock turn these blocks into C/C++ code and upload it. S4A works differently: the PC runs the blocks and sends commands to the connected board over USB.

Frequently asked questions

Is Arduino a programming language?

No. Arduino code is C++ plus the Arduino framework, a set of functions and libraries for common tasks such as reading pins and sending serial data. A standard C++ compiler builds every sketch.

What is the difference between MicroPython and CircuitPython?

MicroPython is the original Python 3 implementation for microcontrollers, started by Damien George. CircuitPython is Adafruit’s fork of MicroPython (a separate project built from the MicroPython code) for Adafruit boards and beginners. The language is almost the same. The most visible difference: a CircuitPython board appears as a USB drive, and saving code.py on it runs the program immediately. With MicroPython, you usually copy files with a tool such as Thonny.

Which microcontroller should I buy to start learning?

The Arduino Uno R3, because of its simplicity and because most Arduino tutorials are written for it. If you want Wi-Fi and Bluetooth from the start, the ESP32 is an affordable alternative. For MicroPython, the Raspberry Pi Pico is a low-cost option.

Where to start

If you are new, start with an Arduino Uno, as I did. Install the Arduino IDE and upload the Blink sketch; my Arduino Programming Basics guide shows both steps. If the upload fails, check pins 0 and 1: on the Uno R3 they share the serial line with the USB connection. When my HC-05 Bluetooth module was wired to them, the Arduino IDE reported an upload error. Disconnect such a module while you upload.

Once Blink works, add actuators (parts that move something, such as motors and servos) and wireless control. My 6-DOF robotic arm with Bluetooth control moves six servos from a phone app over an HC-05 module (6-DOF means six degrees of freedom, six independently moving joints). After that, try MicroPython on an ESP32 for quick prototypes, or move to PlatformIO when your projects grow.

Leave a Comment