moved explanatory content below the broken code in

main so that the exercise functions more like a quiz
This commit is contained in:
Alexander Sisco 2025-02-11 11:56:57 -08:00
parent 20596bc290
commit a7cd808bb8

View File

@ -68,9 +68,107 @@ const testing = std.testing;
pub fn main() !void {
var PORTB: u4 = 0b0000; // only 4 bits wide for simplicity
// The LCD display on our robot is not behaving as expected. In order to
// get it functioning properly, we must initialize it by sending the
// correct sequence of half-bytes to PORTB's lower four pins.
//
// Let's first take a look at toggling bits.
// See if you can solve the following problems to get the lcd working and
// reveal the message our robot has stored in his EEPROM.
//
// .--. .--.
// | | | |
// +--------------------------+
// | +----------------------+ |
// | | | |
// | | XXXXXXXX XXXXXXXX | | <-- LCD
// | | | |
// | +----------------------+ |
// | _________ |
// | |_|_|_|_|_| |
// | |
// +--------------------------+
// | |
//
// The last two problems throw you a bit of a curve ball. Try solving them
// on your own. If you need help, scroll to the bottom to see some in depth
// explanations on toggling, setting, and clearing bits in Zig.
print("Toggle pins with XOR on PORTB\n", .{});
print("-----------------------------\n", .{});
PORTB = 0b1100;
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("^ {b:0>4} // (bitmask)\n", .{0b0101});
PORTB ^= (1 << 1) | (1 << 0); // What's wrong here?
checkAnswer(0b1001, PORTB);
newline();
PORTB = 0b1100;
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("^ {b:0>4} // (bitmask)\n", .{0b0011});
PORTB ^= (1 << 1) & (1 << 0); // What's wrong here?
checkAnswer(0b1111, PORTB);
newline();
print("Set pins with OR on PORTB\n", .{});
print("-------------------------\n", .{});
PORTB = 0b1001; // reset PORTB
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("| {b:0>4} // (bitmask)\n", .{0b0100});
PORTB = PORTB ??? (1 << 2); // What's missing here?
checkAnswer(0b1101, PORTB);
newline();
PORTB = 0b1001; // reset PORTB
print(" {b:0>4} // (reset state)\n", .{PORTB});
print("| {b:0>4} // (bitmask)\n", .{0b0100});
PORTB ??? (1 << 2); // What's missing here?
checkAnswer(0b1101, PORTB);
newline();
print("Clear pins with AND and NOT on PORTB\n", .{});
print("------------------------------------\n", .{});
PORTB = 0b1110; // reset PORTB
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("& {b:0>4} // (bitmask)\n", .{0b1011});
PORTB = PORTB & ???@as(u4, 1 << 2); // What character is missing here?
checkAnswer(0b1010, PORTB);
newline();
PORTB = 0b0111; // reset PORTB
print(" {b:0>4} // (reset state)\n", .{PORTB});
print("& {b:0>4} // (bitmask)\n", .{0b1110});
PORTB &= ~(1 << 0); // What's missing here?
checkAnswer(0b0110, PORTB);
newline();
newline();
}
// ************************************************************************
// IN-DEPTH EXPLANATIONS BELOW
// ************************************************************************
// ------------------------------------------------------------------------
// Toggling bits with XOR:
// ------------------------------------------------------------------------
@ -102,27 +200,15 @@ pub fn main() !void {
// We can think of these bits having flipped
// because of the presence of 1s in those columns
// of our bitmask.
print("Toggle pins with XOR on PORTB\n", .{});
print("-----------------------------\n", .{});
PORTB = 0b1100;
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("^ {b:0>4} // (bitmask)\n", .{0b0101});
PORTB ^= (1 << 1) | (1 << 0); // What's wrong here?
checkAnswer(0b1001, PORTB);
newline();
PORTB = 0b1100;
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("^ {b:0>4} // (bitmask)\n", .{0b0011});
PORTB ^= (1 << 1) & (1 << 0); // What's wrong here?
checkAnswer(0b1111, PORTB);
newline();
//
// Now let's take a look at setting bits with the | operator.
//
// ------------------------------------------------------------------------
// Setting bits with OR:
// ------------------------------------------------------------------------
@ -164,29 +250,15 @@ pub fn main() !void {
// we can rewrite our code again in an even more compact and idiomatic
// form: PORTB |= (1 << 1)
print("Set pins with OR on PORTB\n", .{});
print("-------------------------\n", .{});
PORTB = 0b1001; // reset PORTB
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("| {b:0>4} // (bitmask)\n", .{0b0100});
PORTB = PORTB ??? (1 << 2); // What's missing here?
checkAnswer(0b1101, PORTB);
newline();
PORTB = 0b1001; // reset PORTB
print(" {b:0>4} // (reset state)\n", .{PORTB});
print("| {b:0>4} // (bitmask)\n", .{0b0100});
PORTB ??? (1 << 2); // What's missing here?
checkAnswer(0b1101, PORTB);
newline();
// So now we've covered how to toggle and set bits. What about clearing
// them? Well, this is where Zig throws us a curve ball. Don't worry we'll
// go through it step by step.
// ------------------------------------------------------------------------
// Clearing bits with AND and NOT:
// ------------------------------------------------------------------------
@ -263,31 +335,11 @@ pub fn main() !void {
// PORTB &= ~@as(u4, 1 << 2);
//
print("Clear pins with AND and NOT on PORTB\n", .{});
print("------------------------------------\n", .{});
PORTB = 0b1110; // reset PORTB
print(" {b:0>4} // (initial state of PORTB)\n", .{PORTB});
print("& {b:0>4} // (bitmask)\n", .{0b1011});
PORTB = PORTB & ???@as(u4, 1 << 2); // What character is missing here?
checkAnswer(0b1010, PORTB);
newline();
PORTB = 0b0111; // reset PORTB
print(" {b:0>4} // (reset state)\n", .{PORTB});
print("& {b:0>4} // (bitmask)\n", .{0b1110});
PORTB &= ~(1 << 0); // What's missing here?
checkAnswer(0b0110, PORTB);
newline();
newline();
// ------------------------------------------------------------------------
// Conclusion
// ------------------------------------------------------------------------
//
// While the examples in this exercise have used only 4-bit wide variables,
// While the examples in this quiz have used only 4-bit wide variables,
// working with 8 bits is no different. Here's a an example where we set
// every other bit beginning with the two's place:
@ -312,7 +364,8 @@ pub fn main() !void {
// PORTD = ~PORTD;
// print("PORTD: {b:0>8} // bits flipped with NOT (~)\n", .{PORTD});
// newline();
}
// ----------------------------------------------------------------------------
// Here are some helper functions for manipulating bits