I've programmed the Arduino and have started programming the Teensy. They are similar to C but there are slight nuances in the programming language.

For instance, in Arduino's C you call a function pinMode(pin#, Output/Input) to designate a digital pin to either output signals or receive signals. In Teensy's C, you set the "DDR" register associated with one of four ports (each of which represents a collection of pins) which you collectively designate as either input or output (Teensy IO syntax).

I would like to know if it is the case that when you use a microcontroller that is new to you, you need to effectively learn a new "language". I put the word "language" in quotes because despite the nuances in syntax, the components and how they are set up in software are fundamentally equivalent e.g., the notion of ports and pins still refer to a terminal from which you can output/input digital signals.

In the same vain of discourse: are there microcontrollers that aren't programmed in software or will there always be a software layer used to program the uController? If the latter, who writes/provides documentation for them?

  • 2
    \$\begingroup\$ The programming language for Arduino is C++ (not (only) C) - or perhaps just a subset of C++ (or even Processing). It is not entirely clear, but it is certainly more than C; for instance it has classes and user-definable operator +=. \$\endgroup\$ Commented Nov 25, 2015 at 18:41
  • 1
    \$\begingroup\$ It is C++, it compiles using g++-avr. Technically it would be a freestanding C++ implementation, and it does not include the C++ standard library (due to things like dynamic memory allocation and exceptions being necessary). You can use language features like classes and templates, I have seen a template-based digitalWrite() replacement that achieves the same performance as directly accessing registers, the Arduino method has quite the overhead. \$\endgroup\$
    – r_ahlskog
    Commented Nov 26, 2015 at 6:08
  • 1
    \$\begingroup\$ The language is the same. It's the API that's different. If you move away from microcontrollers and start writing desktop apps you'll face exactly the same problems when writing C programs for Windows, Linux and Mac. Even if you use purely POSIX API (which all 3 platforms support) you'll still hit platform specific differences when you want to save user's settings/preferences. \$\endgroup\$
    – slebetman
    Commented Nov 26, 2015 at 8:20

8 Answers 8


Microprocessors and Microcontrollers will typically use a shared architecture between different product and manufacturer lines. These architectures typically define a low level command set (instruction set) common to all implementations. A C or C++ compiler will be able to generate bytecode executable on all e.g. ARM processors.

However, the architecture is only half the picture. Since there are lots of specific memory addresses, on board peripherals, memory management and other implementation details that the architecture doesn't address

A manufacturer or third party will typically provide a collection of source files (an HDK) that will provide definitions, port mappings, and example code. Typically the HDK is for C and C++. Typically the HDK will have a demonstration board associated with it (think $500 arduino). A lot of detailed configuration work is often necessary to adjust the development/sample platform to the device you are designing

The Arduino is based on the AVR architecture and is primarily supported by Atmel. Arduino has created a platform bootloader and a library of simplified C++ functions and objects for you to use the platform with minimal effort. The Arduino platform and IDE is designed for hobbyists with minimal equipment. Before the arduino, the PIC fulfilled a similar role with an easy to use and cheap BASIC environment.

In a professional environment typically this support is provided by the vendor/manufacturer or is contracted out to a third party. They provide the low level code and headers and you write your application with that HDK, in larger organizations this could be done in house. There is a recent trend for manufacturers to build an open API/Software ecosystem around their platform that makes them as easy to use right out of the box as the arduino. There are still countless chips with very little programming support, and most platform knowledge locked away in the corporate world.


The language in this case is exactly the same. The Arduino environment happens to have some extra libraries (just more C code) that 'wrap' the access to the actual hardware registers (DDRx, PORTx, INx, etc.) with slightly more user-friendly functions. This increases the overhead (more instructions need to be executed for the same operation) but increases flexibility as it is "simple" to write a program that uses only these calls, then retarget it for a different chip (say, an arduino mega) and the library will handle the proper mapping internally.

There aren't really any 'standard' APIs for really low-level access across chips from different vendors. However, all of the low-level access is done in the same way - reads and writes to fixed memory addresses - so the overall access method will be similar between different parts, just the details and names will be different. Perhaps one will just provide header files with huge lists of #defines register addresses cast to pointers. Or perhaps the header files will use structures to keep things organized with a bit of a hierarchy. Some manufacturers may also provide higher-level APIs. This can be very useful for peripherals which are complex and difficult to configure. GPIO is very simple, but something like a USB controller with DMA support could have hundreds of registers. Generally API documentation will be provided with the vendor-supplied toolchain.

So the bottom line is yes, you will need to learn some new register names, but the language is still C++ (or C, assembly, or perhaps something more esoteric).

  • 4
    \$\begingroup\$ Arduino isn't quite just C (actually, C++) - it's got a preprocessor that makes a few changes before feeding it to the C compiler. \$\endgroup\$ Commented Nov 25, 2015 at 10:36
  • \$\begingroup\$ Actually, for Arduino, it is more than C. It is C++ (or perhaps a subset of C++). \$\endgroup\$ Commented Nov 25, 2015 at 18:48
  • \$\begingroup\$ Is it just native C++ with Arduino libraries, or something more? \$\endgroup\$ Commented Nov 26, 2015 at 1:54
  • \$\begingroup\$ The Arduino IDE apparently does a bit of extra pre-processing on top of otherwise standard C++. Most IDEs do not do this. \$\endgroup\$ Commented Nov 26, 2015 at 7:07
  • \$\begingroup\$ It's basically C++ but with main() pre-defined for you. Instead you get two entry points: init() and loop() (correct me if I'm wrong but I've only touched Arduino with a 20ft pole) \$\endgroup\$
    – slebetman
    Commented Nov 26, 2015 at 8:22

You are confusing microcontrollers and compilers. The high level languages you can program any particular micro in is a function of what compilers are available for that micro.

At the low level, the micro executes machine instructions, which a compiler derives for the text file you give it that you consider to be the "program". You are really specifying some logic to perform, and the compiler figures out how to use the available machine instructions to implement that logic. In this case, what you program in is a function of the compiler, not the micro's native instruction set.

You can program a micro by specifying native instructions directly. This is done by using assembly language. Like a compiler, the assembler is a translator that takes a text file you write and produces machine instructions as a result. The difference is that in this case you are specifying those machine instructions directly. Each instruction is given a name, and you write these names instead of the binary opcodes, but you are still specifying the instructions directly. The assembler only does the grunt work of figuring out the exact binary encoding of each instruction from the name and options you write in the text file.

While a high level language can be the same across very different micros, the machine instructions are usually only similar within a family of related micros. For example, all the Microchip PIC 18 have the same instruction set (mostly), which is different from the basic PIC 16, and different again from the 16 bit parts like the PIC 24 and dsPIC 30 and 33.

  • 1
    \$\begingroup\$ The assembler also resolves labels for jump statements, which is highly error-prone when done by hand. \$\endgroup\$ Commented Nov 25, 2015 at 14:35

The programming language is still C. But the library of the manufacturer to access the hardware differs. As far as I know there is no standard so every manufacturer has its own API. If you want to be portable between different manufacturers you may want to introduce your own abstract API to access the hardware with specific implementations which map your API to the manufacturer specific methods.

  • \$\begingroup\$ Actually, it is more than C. It is C++ (or perhaps a subset of C++). \$\endgroup\$ Commented Nov 25, 2015 at 18:47

Other answers have made the distinction between high-level languages (such as C++) and machine code, though I do not believe that invalidates your statement that each microcontroller has an associated 'language'.

The differences of language implementations are not large enough to be classified as different languages, though I would not hesitate to differentiate them into 'dialects'. Two layers of change can exist here.

  1. High-level wrapper libraries may be available from the manufacturer or some third party
  2. Certain compilers may not emit standard-compliant code

Let's take these points while observing the Arduino platform.

  • The Arduino community provides heavily abstracted C++ libraries for AVR architecture chips. These libraries suggest different control flow from what one might expect from a typical C++ program (e.g. the hiding of main()).
  • Under the hood, Arduino compiles its code using avr-gcc, which emits C/C++ code. Exceptions are not well-supported on AVR chips, however, and are almost always disabled. With such a large feature missing, the resulting program might not act like how a 'regular' C++ program would.

Knowing this, how do you decide how to program any arbitrary microcontroller? You have several options:

  1. Search for community-made libraries and IDEs for your specific chip. AVR chips are sometimes developed using only C, but the Arduino project provides a more user-friendly experience for hobbyists.
  2. Find compilers which are able to compile for your specific chip. With the proper compiler, your chip's datasheets, and some amount of patience, you will be able to write code very close to the metal.

For reference, here is a list of supported backends for GCC. You will notice there's support for ARM, AVR, MIPS, and a few others.

About chips which aren't programmed with 'software'...

You might want to look into field-programmable gate arrays (FPGAs)! FPGAs are controlled by changing the values of look-up tables to emulate logic gates. This has no corresponding software form, per se, but is still developed using hardware description languages such as VHDL and Verilog.


I look at one pcboard and see some surface mount devices, some resistors and capacitors and leds. Does that mean that because one of those boards is a video card, all boards with resistors and capacitors and multiple layers and traces are all video cards? Nope.

Here is another example, this web page uses the english alphabet and english words. So does the new york times website, does that make this website the new york times? No they just share the same alphabet and language but are otherwise completely different.

C is a general purpose programming language that abstracts the instruction set below it. Can be used for bare metal, can be used to create different and incompatible to each other operating systems, can be used to create video games, etc. All of which use the same basic C language, some common C functions and constructions as well as function calls they have created that are specific to the target application. For each of those platforms you mention or others there may be a set of functions someone chose to create. Just like a handful of people so far including myself have given you the same answer but written it in a different way. Take 100 programmers and isolate them from each other and give them a programming task to solve a particular problem, without completely constraining their programming freedom, and you will get anywhere from 1 to 100 different, incompatible to each other solutions, likely not 1 but several common themes depending on their training and experience, and then variable names and function names that as a set are likely unique to each individual. Take the same boards you are already talking about and you will find that I certainly have my own C code that is incompatible (with the arduino functions) to run on them, as with many others, as well as incompatible with other platforms. That is the beauty of bare metal embedded programming, you are not constrained in any way, you dont have to live within the operating systems standard library calls or the guis limited set of rules, etc. complete freedom.

You may choose, and a high percentage of folks do, to play in someone elses sandbox rather than building your own, meaning use the arduino gui and their C libraries.

You can take the same pc and run different versions of windows it, linux, bsd, and a laundry list of other operating systems which at some level are using C but whose function calls are incompatible with each other. Same hardware and incompatible C, which extends to different hardware, same language, can have compatible or incompatible code. The language in no way makes them compatible.

C is used on these embedded platforms because that is the common practice, there is no other language that can replace C for this. First step for a new processor is assembly of course then almost always is C next, then maybe others if it is powerful enough to run an operating system (linux, bsd, etc). C was invented and hoped to solve the at the time problem of porting code across platforms, and so long as you have an operating system that is the case a C compatible compiler making code that RUNS ON AN OPERATING SYSTEM, will do the standard C file operations and printf and such things. But bare metal is a different story there is no operating system there is often no notion of a file system nor a display, but by common practice there is likely a C compiler which at its roots turns C into target specific assembly language. So we cheat the original idea of C bridging the gap between different computers to aid code portability, and we make because of personal choices of different individuals incompatible library calls for a specific target.

  • \$\begingroup\$ Actually, for Arduino, it is more than C. It is C++ (or perhaps a subset of C++). \$\endgroup\$ Commented Nov 25, 2015 at 18:49

To answer your second question, the term "microcontroller" implies that the chip has a CPU and RAM (and probably ROM) on board. All microcontrollers run software -- that's why we like them.

Going deeper into the first question, note that while (almost?) all MCUs have a C compiler, the basic C language does not support every instruction on every processor. For example, C has shift left/right operators, but no rotate left/right operators. C's pointer system doesn't naturally support separate program and data address spaces (as in some Harvard Architectures). C has no direct SIMD support.

Compilers have a few options for dealing with these features:

  1. Extend the base language, usually with new keywords (e.g. near and far for paged memories).

  2. Provide intrinsic functions (e.g. __ror() and __rol() for rotation).

  3. Work them into the optimizer so that sequences of C operations get compiled into one efficient instruction (e.g. a multiply/accumulate).

  4. Ignore them and make the user write assembly code if they want non-C-standard features.

The next level up is the manufacturer-provided header files that mainly define all of the registers for you. You could make these yourself, but it's a big pain unless you're an expert on that MCU.

Finally, there's manufacturer-provided library functions, which handle the low-stuff like register writes for you.

Your example mixes two levels. DDR is a macro that refers to a register. It's implemented as either a pointer access or a compiler intrinsic function (I forget which). pinMode() is a function that writes to the DDR register for you.

When you go from one MCU line to another, you'll have to learn new registers and new compiler quirks. If you stay within the same company, you might get a similar API. Different companies don't share APIs; why would we help you switch to our competitors? :-)


Microcontrollers often have different microcodes at the hardware level. To save us from inputting machine code (i.e. instructions in the form of numbers - each one representing the microcontroller's raw microcode) or in symbolic assembler (which provides a mnemonic label for each machine code instruction), portable high-level languages are used.

C and Forth are designed deliberately to be easily portable across different machine code sets.

So if you use C on the Arduino, and C on the Teensy, you are using C in both cases.

If you used Forth on the Arduino, and Forth on the Teensy, you would be using Forth on both cases.

Sometimes, additional hardware facilities will prompt the person (or group) porting the language to the new hardware to write some pre-fabricated code to let you access the new facilities of the hardware platform, without having to write a lot of low-level code yourself.

These libraries (in C) or dictionaries (in Forth) can have some hardware-specific functions or words in them.


Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.