01. Embedded C & Getting Started with Keil μVision
C on a PC and C on a microcontroller use the same language but a different mindset. On a tiny chip with no OS and no screen, code drives the hardware directly. We learn what embedded C is, how Keil μVision (C51 / MDK-ARM) builds·debugs·simulates code, and the standard embedded program skeleton (main + while(1)). You can follow along with PC gcc even without a board.
What you'll learn
- 1Explain how embedded C differs from regular PC programming
- 2Tell apart Keil μVision's two flavors (C51 / MDK-ARM) and their target chips
- 3Understand the standard embedded skeleton (main + while(1) infinite loop)
- 4Follow μVision's build (F7) → debug/sim (Ctrl+F5) flow
- 5Build and run a pure-logic example with gcc
Introduction
An embedded system is a computer built into a machine to do one job — the small chip (MCU) inside a microwave, washing machine, drone, or car ECU. Embedded C uses the same syntax as standard C but **manipulates memory addresses directly**, **operates hardware registers bit by bit**, and runs with **very limited resources** (a few KB of RAM).
This lesson doesn't touch a real board (8051·STM32) yet. We write portable, pure C logic and get a feel for μVision's workflow and the simulator. Every example also runs on PC gcc.
Key concepts
1) PC program vs embedded program
| Aspect | PC | Embedded |
|---|---|---|
| OS | Yes | Often none (bare-metal) |
| Exit | ends when main returns | runs forever via while(1) |
| I/O | screen·keyboard·files | GPIO pins·sensors·registers |
| Resources | GBs of RAM | KBs of RAM |
| Debugging | console output | LED toggle·UART·debugger |
2) Keil μVision — C51 vs MDK-ARM
| Tool | Target chip | Lessons |
|---|---|---|
| Keil C51 | 8051 family (AT89C52…) | 6–12 |
| Keil MDK-ARM | Arm Cortex-M (STM32F103…) | 13–20·24 |
3) The standard embedded skeleton
int main(void)
{
/* 1. Init: clocks·pins·peripherals (once) */
while (1) {
/* 2. Body: read sensors·decide·output ... repeat forever */
}
/* never reached */
}Before main runs, **startup code** sets up the stack and initializes globals, then jumps to main. Keil's device pack includes this file, so we just write main onward.
4) Build → debug → simulate
- **F7 (Build)** — compile·link into an executable image
- **Ctrl+F5 (Debug)** — start the debugger; in simulator mode it mimics the chip with no board
- While debugging, **F11** (step) and **F5** (run) let you watch registers·variables
Core example
On a real board a GPIO pin would drive the LED instead of the led variable. Here we mimic it with a variable and printf to feel "state changes inside the infinite loop" (limited to 5 iterations for PC观察).
#include <stdio.h>
#include <stdint.h>
int main(void)
{
uint8_t led = 0; /* 0=off, 1=on */
uint8_t tick;
printf("Hello, Embedded C!\n");
for (tick = 0; tick < 5; tick++) {
led = (uint8_t)!led; /* toggle LED */
printf("tick %u: LED = %s\n",
(unsigned)tick, led ? "ON" : "OFF");
}
return 0;
}gcc main.c -o main && ./main
# Hello, Embedded C!
# tick 0: LED = ON
# tick 1: LED = OFF ... (ON/OFF repeats)This track's approach: "pure logic on PC (gcc), hardware control on the simulator." Splitting a decision like toggle into a toggle() function lets you unit-test it without hardware.
Common mistakes
Q. Why doesn't embedded main return?
A. A bare-metal MCU has no OS to return to. If main returns, there's nowhere to go and you fall into undefined behavior. So real embedded main ends with while(1) and never returns. This example exits on purpose, just for PC observation.
Q. int works — why use uint8_t and friends?
A. int size varies by MCU (16-bit on 8051), and registers have exact widths. uint8_t/uint16_t/uint32_t carry their width in the name, so intent and portability are clear (more in lesson 2).
Q. It works on gcc — is this really embedded learning?
A. Toggling, infinite loops, and data types are hardware-independent C foundations. We lay them quickly on PC, then apply the same ideas to real chip registers from lesson 6.
Summary
- Embedded C drives hardware directly, without relying on an OS or abundant resources
- Keil μVision splits into C51 (8051) and MDK-ARM (STM32) but shares one IDE
- The embedded skeleton is init + while(1); main never returns
- μVision flow: F7 (build) → Ctrl+F5 (debug/sim) → observe via windows
- Verify pure logic quickly with gcc
Exercises
- Change the toggle message to a sentence with your name and rerun with gcc
- Split the toggle logic into a toggle(state) function and unit-test it in pc_test.c
- Download a Keil MDK-Arm (or C51) eval, create an empty project, and confirm F7 builds
All lecture materials and example code (with homework and answers) are openly available on GitHub.
View on GitHub ↗