diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..2bc152073b6e68806f7632836d296aee5dabeb17
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,4 @@
+build
+*.swo
+*.swp
+.DS_Store
diff --git a/01_hello_world/.gitignore b/01_hello_world/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..15f47d081a203b85d98f53f0869208b20f1a3da4
--- /dev/null
+++ b/01_hello_world/.gitignore
@@ -0,0 +1,2 @@
+hello_world_c
+hello_world_cpp
diff --git a/01_hello_world/Makefile b/01_hello_world/Makefile
new file mode 100644
index 0000000000000000000000000000000000000000..7f8f9f513f97b7c6a56056bd0a9eae526e93ad4f
--- /dev/null
+++ b/01_hello_world/Makefile
@@ -0,0 +1,34 @@
+# Change your compiler here if you're not using gcc. CC is for C, and CXX is for C++.
+CC = gcc
+CXX = g++
+
+# These are options that we pass to the compiler. They say to emit all warnings ("warn all"), and
+# optimize the program aggresively to make it fast ("optimization level 3").
+CFLAGS = -Wall -O3
+
+# This line is here so that by default, Make will build both programs. It's not strictly necessary.
+# With or without this line, you can run "make hello_world_c" or "make hello_world_cpp". With this
+# line, if you just run "make" you'll get both. (Make executes the first rule in the Makefile when
+# you don't give it a target specifically, so we put this rule first.) We tell Make that this rule
+# is "phony" so that it understands it's just a combination of other rules and doesn't produce any
+# of its own files.
+.PHONY: all
+all: hello_world_c hello_world_cpp
+
+# These are essentially recipes for programs. The first line tells Make that we are going to build
+# a program "hello_world_c" from the source file "hello_world.c". The second lines Make how to
+# do it; Make basically copies and pastes this line into the terminal. Note that to use the compiler
+# and options we defined earlier (CC, CXX, and CFLAGS), we have to enclose them in parentheses and
+# add a dollar sign.
+hello_world_c: hello_world.c
+	$(CC) $(CFLAGS) -o hello_world_c hello_world.c
+
+# Here's the same thing except for the C++ version.
+hello_world_cpp: hello_world.cpp
+	$(CXX) $(CFLAGS) -o hello_world_cpp hello_world.cpp
+
+# This rule deletes all the binaries. It's declared "phony" which means it doesn't actually make
+# anything. Otherwise Make would get confused about when it should run this rule.
+.PHONY: clean
+clean:
+	rm hello_world_c hello_world_cpp
diff --git a/01_hello_world/README.md b/01_hello_world/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..f8f9231e5bd1e60b6f54afc9b459fcc90ecabd30
--- /dev/null
+++ b/01_hello_world/README.md
@@ -0,0 +1,21 @@
+# Hello World
+
+From this directory (i.e. first run `cd /wherever/you/put/this/repo/01_hello_world`), run `make`. If
+your toolchain is installed correctly, this will build two programs: `hello_world_c` and
+`hello_world_cpp`. You can run them like this: `./hello_world_c` and `./hello_world_cpp`.
+
+```
+demo@linux:01_hello_world$ make
+gcc -Wall -O3 -o hello_world_c hello_world.c
+g++ -Wall -O3 -o hello_world_cpp hello_world.cpp
+demo@linux:01_hello_world$ ./hello_world_c
+hello, world, I'm C
+demo@linux:01_hello_world$ ./hello_world_cpp
+hello, world, I'm C++
+```
+
+Note: Putting `./` in front of the executable files tells the shell unambiguously that you want to
+run the programs located in this directory. The shell will say something like `command not found` if
+you leave it out. This might seem annoying, but it's really important from a security perspective.
+Otherwise if you made a program called `cd` or `make` or something, you could accidentally run it
+and it might do something bad.
diff --git a/01_hello_world/hello_world.c b/01_hello_world/hello_world.c
new file mode 100644
index 0000000000000000000000000000000000000000..b57adc801dd96b424f2a60ac9596a9be2af4b0ab
--- /dev/null
+++ b/01_hello_world/hello_world.c
@@ -0,0 +1,6 @@
+#include <stdio.h>
+
+// Every C program has a function called main. This is where your program starts.
+int main(void) {
+    printf("hello, world, I'm C\n");
+}
diff --git a/01_hello_world/hello_world.cpp b/01_hello_world/hello_world.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..614631986ed0f64780f2bfb060e7d0a6c9ed56b3
--- /dev/null
+++ b/01_hello_world/hello_world.cpp
@@ -0,0 +1,7 @@
+#include <iostream>
+
+// C++ uses a main routine just like C. We could use printf here, too, but it's more idiomatic to
+// use std::cout.
+int main() {
+    std::cout << "hello, world, I'm C++\n";
+}
diff --git a/README.md b/README.md
index 25979186df0a0ef8bb7af1992933268a29355b65..1c9d10ce37efb1ed0ee2d75cf4ce76afb0bc163e 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,51 @@
-# c_cpp_and_make
+# C, C++, and Makefiles
 
-Hello world programs for C and C++, built with Makefiles.
\ No newline at end of file
+Microcontrollers are great and all, but if you're new to programming it can help to learn a bit
+about the software tools on their own before diving into the hardware as well. This repo has some
+example programs in C and C++, along with Makefiles that help you build them.
+
+## The Basics
+
+C is a programming language. It was created in the early 70s at Bell Labs by Dennis Ritchie and Ken
+Thompson. This makes it quite old, as far as programming languages go, but it certainly wasn't the
+first (Fortran, Lisp, COBOL, and BASIC are all older, to name a few). And it's still widely used
+today -- number one, in fact, in some popularity [rankings](https://www.tiobe.com/tiobe-index/).
+
+C++ is an extended version of C, created by Bjarne Stroustrup in the 80s. The syntax is basically
+the same, so usually any C program you write will also be a valid C++ program. The original
+difference is that C++ is [object
+oriented](https://en.wikipedia.org/wiki/Object-oriented_programming) (basically, allows you to
+associate data and methods with "classes"), but since then it's had all sorts of other stuff bolted
+on too (like [templates](https://en.wikipedia.org/wiki/Template_(C%2B%2B)),
+[lambdas](https://stackoverflow.com/questions/7627098/what-is-a-lambda-expression-in-c11), etc.). C
+and C++ are commonly used together.
+
+Unlike Python or JavaScript, C and C++ are compiled languages. This means that before you run your
+program, you always convert it into a binary format that your computer can execute directly. This is
+called building your program, and it is done by a compiler. To run code on your own computer, you'll
+almost certainly end up using [gcc](https://gcc.gnu.org/), [clang](https://clang.llvm.org/), or
+[MSVC](https://visualstudio.microsoft.com/vs/features/cplusplus/). The first two are usually run
+from the command line, while the third is integrated into Visual Studio. We'll be using the UNIX
+style command line exclusively, so even if you run Windows, it's recommended that you install a
+command line toolchain.
+
+## Required Software
+
+Overall, we'll need a compiler, and [Make](https://www.gnu.org/software/make/).
+
+On Linux, if these tools aren't installed already, you can use your package manager. Most distros
+have one package that has all the basic tools bundled together. On Ubuntu, for example, you can run
+`sudo apt install build-essential`.
+
+On Mac, if you've installed XCode, you already have clang. (You may need to tell XCode to install
+the command line tools specifically for it to show up on your path.) You can also use homebrew to
+install gcc. One gotcha is that Apple decided to alias clang as gcc in the stock install. So if you
+run gcc, you'll actually get clang. This is bad because not all the options are the same, so
+sometimes it just won't work to switch between the two. So if you do install gcc with homebrew,
+you'll want to run gcc-8 or gcc-9 (or whatever specific version you got).
+
+On Windows... honestly I'm not sure. I haven't set up a development environment there in years.
+
+## Examples
+
+- [hello world](./01_hello_world)