My second year students started this semester having never written a line of code, and are making good progress in computational thinking. They are taking two concurrent intro programming courses this semester. One, which I teach, uses embedded C to program a pre-fab circuit board (this one). The other, which I’ve taught in the past but don’t now, uses Rockwell’s “ladder logic” language for programmable logic controllers.
I wrote previously about using Mark Guzdial’s approach of “worked examples and self-explanations,” and the results are very good so far. The students were very quickly able to make sense of compiler errors, decode data sheet register descriptions, troubleshoot their programs’ run-time behaviour, and combine their code snippets into novel (to them) programs. So far they can control buttons, LEDs, buzzers (using pulse-width modulation), and interrupt-driven timers.
Embedded Systems: The Bottom of the Ladder of Abstraction
I was pretty worried about introducing programming using an embedded language — I thought that working with a system that has no keyboard, mouse, or monitor would be a bit alienating, but that hasn’t been the case at all. If anything, the reverse is true — there’s something very grounded about immediately seeing your code control something outside the computer.
Look Ma, No Variables (Yet)
The other advantage of starting with an embedded language is that we were able to do the first two units (Digital I/O and Timers/Buzzers) without ever using a variable. Ergo: I was able to delay explaining variables for about a month, with its attendant conceptual minefield of data types, type hierarchy and promotion, variable scope, etc. We talked about 8-bit registers, of course, but only as “a collection of flip-flops” that are permanently assigned to a single task — starting with bits whose logical value controlled a voltage that turned on a light. This allowed the students to get a feel for assignment, sequence of execution, and timing, without getting bogged down.
In each worked example, I introduced one new syntactical item — first a while loop, then #DEFINE, then an if statement. We talked about it a bit but didn’t include it on quizzes. After four weeks of teaching the micro to do tricks like blink lights and make piercing noises, we started the official “syntax” unit. Here’s what the students can consistently do:
- choose a data type for a particular situation
- predict the outcome of a mixed-type evaluation
- predict the result of a mixed-type assignment
- evaluate logical operations with up to 4 terms — whether they’re sensible or not (examples like “Button1 == PRESSED || Button2 == PRESSED” as well as “6 && (5 < 3) == FALSE”)
- convert between case statements and if statements
- convert between while, for, and do loops
What’s Going Well
Removable chip. In the past, I’ve often noticed students having trouble distinguishing between what’s “inside” the “computer” and what’s “outside.” For example, they will have trouble distinguishing a set of LEDs from the microcontroller pins that control them. Using a demo board with a socketed through-hole microcontroller helps clarify this a bit — especially since our programmers are the out-of-circuit “burn and learn” type where the IC has to be removed from the board and placed in the programmer. With in-circuit programming, students tend to see a circuit-board as an undifferentiated lump — the entire PCB appears to them to be the micro.
Cross compiling. It can be hard to talk about what a compiler really does when students see compiling as “running a program” and executing their code as “running a program.” In an embedded system, the compiling happens on the desktop computer, and the executing happens in a circuit-board on your bench.
Two languages. Comparing two vastly different languages and platforms (microcontroller C vs. PLC ladder logic) helps us talk about what is a general concept of programming and what is a specific feature of a platform or manufacturer. Because ladder logic is interpreted in something called a “scan cycle” (it does not execute every instruction one after the other), it was especially helpful in sorting out flow control.
Worked examples. As Guzdial suggests, making students type in their code makes them very attentive to syntax, capitalization, etc — without me having to sedate them with an explanation. Normally I’d be inclined to steer them away from those superficial features, maybe started with flow charts or something. But they seem to really benefit from thinking about why those symbols are there. The worked examples also mean that students are building up a library of code snippets that they can string together and modify.
Individual examples. Since every student gets a different code example, they are oddly entertained by typing them in to find out what they do (if everyone had the same one, it would only be entertaining for the first person).
Free online textbook. It’s nothing fancy, and there a few grammar mistakes, but the students have been making good use of it, and the diagrams are especially good. Students refer to it for syntax and use it to understand the peripherals that are available and what they do.
Problets. My students are addicted to these online exercises for evaluating and correcting tiny fragments of code. These have really helped students make sense of the sequence of execution, and how to keep track of changing variables. The feedback you get when you make a mistake is unusually helpful (for a compiler). Plus, the author makes them available for free.