Le programme d'un microcontrôleur est généralement appelé firmware ou micrologiciel.
À l'origine, les microcontrôleurs se programmaient en assembleur. Fortement bas niveau (et donc, intrinsèquement optimisé), l'assembleur posa et pose toujours d'énormes problèmes pour la maintenance et l'évolution des logiciels embarqués. Désormais, on utilise de plus en plus des langages de haut niveau, notamment le langage C, capable de faciliter la programmation de microcontrôleurs toujours plus puissants. Ces compilateurs C présentent généralement certaines restrictions liées aux spécificités des microcontrôleurs (mémoire limitée, par exemple). Le compilateur GCC peut produire du code pour certains microcontrôleurs. Avec l’augmentation de la puissance et de la quantité de mémoire de stockage (FLASH) disponible dans les microcontrôleurs, les programmes de ces derniers peuvent désormais être écrits en C++. Il existe même des framework et plateformes en C++ dédiés à l’embarqué, comme Qtopia, mais l'utilisation de ceux-ci restera limitée aux microcontrôleurs les plus puissants.
Certains microcontrôleurs disposent également de firmware réalisant l'interprétation d'un langage évolué. Ainsi, l’Intel 8052 et le Zilog Z8 ont pu être programmés en BASIC dès leurs débuts. Plus récemment, le BASIC Stamp dispose d'un interprète BASIC en mémoire morte.
Il existe des environnements pour aider au développement de certaines applications. Par exemple, LabVIEW et son langage G permettent de programmer les microcontrôleurs Blackfin d'Analog Devices.
Des simulateurs sont disponibles pour certains microcontrôleurs, comme l'environnement MPLAB de Microchip. Les développeurs peuvent ainsi analyser le comportement du microcontrôleur et du programme, comme s'il s'agissait du composant réel. Un simulateur montre l'état interne du processeur, ainsi que celui de ses sorties. Bien que la plupart des simulateurs ne proposent pas de simuler les autres composants d'un système, ils permettent de spécifier les entrées à volonté. On peut de cette façon créer des conditions qui seraient sans cela difficiles à reproduire dans une implémentation physique. Cela facilite donc l'analyse et la résolution des problèmes. De la même façon, certains logiciels de CAO simulent le comportement du microcontrôleur et des composants qui l'entourent. On peut ainsi afficher les états des entrées et sorties des différents composant au cours de l'exécution d'un programme.
Une fois le programme compilé, le fichier binaire doit être envoyé au microcontrôleur. On utilise soit :
Toutefois, le programme qui a été envoyé peut comporter des bogues (bugs), aussi, pour parvenir à les détecter on peut utiliser un émulateur in-circuit.
Le projet μCLinux vise à faire fonctionner Linux sur des microcontrôleurs et des microprocesseurs dépourvus de MMU. Il est par exemple disponible sur Motorola ColdFire, Blackfin, Intel i960, Motorola QUICC, ARM7-TDMI, NEC V850.