Tutorial: State Machines with C Callbacks

State machine

Many electronics projects involve the device transitioning from one state to another. On a high level, it could be that your project is initially in a state where it awaits input, and once it receives it, it goes to another state where it performs a series of actions, eventually returning back to the initial state. On a lower level, many communications protocols are often simple or increasingly complex state machines. In many cases, an elegantly implemented state machine can simplify your code and make it easier to manage.

There are several methods to implement state machines programmatically starting from simple if-conditions to state variables and switch structures. In this tutorial I’ll cover a slightly more advanced method of using callbacks or “function pointers” as they are implemented in C. This has some performance benefits, makes up for some clean code, and you’ll learn a bit on the way!

State Machines with Conditionals

First, to introduce the idea of a state machine, lets take a simple example: Blinking LEDs. Imagine you want the LED to turn on for a second, and then turn off. We could do it with a simple 2-state machine:

enum states { 
  LED_ON,
  LED_OFF
};

enum states state = LED_OFF;

while(1) {
  if(state == LED_OFF) {
    led_on();
    state = LED_ON;
  } else {
    led_off();
    state = LED_OFF;
  }
  sleep(1); // sleep for a second
}

If you can understand the code above, you have pretty much grasped the fundamentals of state machines. We have some processing specific to given state, and when we want to go to another state, we use a variable (in this example it’s called state) to do that. And by the way, if you haven’t encountered enum before, you should check out Enumerated type in Wikipedia. It’s a very handful tool to add to your C coding arsenal.
Continue reading

Super Simple 50+ kHz Logic Analysis with ATtiny2313 and FTDI Friend

AVR & FTDI logic analyzer

While banging my head against the wall with debugging my PS/2 keyboard thingy, I really wished I had a dedicated logic analyzer (preferably with PS/2 decoder, but even raw binary data would’ve been fine). So I decided to try out a long hatched idea – combine an ATtiny2313 and FTDI for some unlimited-length logic capturing with a PC. You’ll only need:

  1. ATtiny2313
  2. 20 MHz crystal and caps (slower will also work, frequency just defines what baud rates you’ll achieve)
  3. FTDI USB/serial converter, like the FTDI friend from Adafruit
  4. Optionally, some power-stabilizing capacitors, reset pullup and ISP programming header for flashing the firmware

ATtiny2313 is ideal for this, as it has all eight port B pins on one side in numerical order – attaching up to 8 logic lines is really straightforward. With 20 MHz crystal, baud rates close to 1 Mbps can be achieved in fast serial mode. I used Adafruit’s FTDI Friend for really simple (and way faster than most cheap serial adapter dongles) serial to USB conversion – just connect ATtiny RXD pin to TX, and TXD to RX, and you can even get power from the Friend so you’re all set! For crystal and that other stuff, see my ATtiny2313 breadboard header post for schematic, the picture above should fill you in with the rest.

Firmware code

This device has some of the smallest firmware codebases ever (firmware is 128 bytes). All we need to do is to set up UART with desired speed, and have the AVR chip to fire up an interrupt whenever data has been sent, and then use that to send current state of port B (using PINB):

#include <avr/io.h>
#include <avr/interrupt.h>

void USARTInit(unsigned int ubrr_value, uint8_t x2, uint8_t stopbits) { 
  // Set baud rate
  UBRRL = ubrr_value & 255; 
  UBRRH = ubrr_value >> 8;

  // Frame Format: asynchronous, 8 data bits, no parity, 1/2 stop bits
  UCSRC = _BV(UCSZ1) | _BV(UCSZ0);
  if(stopbits == 2) UCSRC |= _BV(USBS);

  if(x2) UCSRA = _BV(U2X); // 2x

  // USART Data Register Empty Interrupt Enable
  UCSRB = _BV(UDRIE);

  // Enable The receiver and transmitter
  UCSRB |= _BV(RXEN) | _BV(TXEN);
}

int main() {
  // 230.4 kbps, 8 data bits, no parity, 2 stop bits
  USARTInit(10, 1, 2); // replace 10 with 4 to get 0.5 Mbps

  sei(); // enable interrupts

  while(1) {}
	
  return 1;
}

ISR(USART_UDRE_vect) {
  UDR = PINB;
}

Continue reading

Minimal PS/2 Keyboard on ATtiny2313

AVR PS/2 keyboard

I recently got myself a mechanical keyboard (to be precise, a Happy Hacking Keyboard Professional 2). One side effect of this switch was, that the new keyboard no longer works with simple passive PS/2 adapter. And the only type of input my current motherboard can be configured to power up on is spacebar from a PS/2 keyboard.

Well, I had read from somewhere that PS/2 protocol is not too complex, so I decided to find out if I could make a simple gadget that would send spacebar keypress over PS/2 when a switch was toggled. That turned out to be quite easy (with some limitations, read the end of this post to find out more).

PS/2 basics

The Wikipedia page for PS/2 connector already looked promising – there are GND and VCC pins straight available, and only two additional (open collector type) lines are needed for data and clock lines. Communication is bi-directional with the keyboard providing clock signal and sending end toggles data line while the receiving end listens.
Continue reading

Olimex and ATtiny2313 breadboard header

This is the final article in my ATtiny2313 breadboard header series. In the previous parts we’ve looked at:

In this part, I’ll have a short review of the PCB ordering process with Olimex, and a bit how the boards turned out. Let’s get going!
Continue reading

USB HID keyboard with V-USB

There still seems to be a lot of traffic to my V-USB tutorials, so I thought I’d write a short follow-up post on USB keyboards. I already did a USB HID mouse post earlier, so you might want to check that out to understand a bit about HID descriptors and associated V-USB settings (in short, human interface devices send a binary descriptor to PC telling what kind of “reports” they send to the host on user activities).

As a basic setup, you’ll need a working V-USB circuit with one switch and one LED attached. Here, I’m using ATtiny2313 with the LED wired to PB0 and switch to PB1. The ATtiny is using 20 MHz crystal, so if you’re following my USB tutorial series and have that circuit at hand, remember to change that frequency in usbconfig.c before trying this out. Note the cool breadboard header I have, there will be more posts about that one to follow soon!
Continue reading

3.3V UART with MAX3232CPE

Before diving right into SPI communications for my SD tutorial, I wanted to have a 3.3V development platform that could output some meaningful status information, not just light a LED if something goes wrong. In this post, I will outline the basic testing platform that will be used in the upcoming part 3 of that tutorial, and discuss a little about UART on AVR in the progress. Here’s what we’ll build:

If you want to build it yourself, you’ll need:

  • ATtiny2313 or other AVR chip with UART pins (RX/TX) separate from SPI pins (MOSI/MISO/SCK)
  • 20 MHz crystal (other speeds will work, too) and ~27 pF capacitors
  • 4k7 pullup resistor for ATtiny2313 RESET pin
  • 3.3V regulator such as LD1086V33 or some other 3.3V voltage source
  • 2 filtering caps for the regulator input/output sides, 10 uF
  • MAX3232CPE or similar RS-232 transceiver that works on a 3.3V voltage
  • RS-232 port on your computer or a USB to RS-232 dongle
  • RS-232 to breadboard connector (home-soldered example seen above)

Continue reading

7 Segment Multiplexing With ULN2003 & PNP Transistors

The reason a started my electronics hobby was that I wanted to build a chess clock. Lacking a proper LCD display, I chose to multiplex several 7-segment displays. Most sources in the net did not specify hardware at all, and those that did were driving the segments with a 74HC595 shift register and using NPN transistors to enable one common cathode display at a time. However, if you look at 74HC595 specs you’ll notice that it’s not designed to source the amount of current that is required to drive several multiplexed 7-segment displays. It might work, but no one can say for how long!

It took me a while to find a good, inexpensive and readily available alternative. I finally found it in ULN2003, which is inexpensive darlington array that can drive 500 mA from each of its pins. So I decided to write a little tutorial on 7 segment multiplexing that walks through all the needed hardware and software in detail. Here’s what we’ll build (click for a larger image):

For this tutorial I assume you know how to connect ATtiny2313 to a programmer and flash it with custom software. You’ll learn as much in IMakeProjects.com’s AVR tutorial. You’ll also need the following components:
Continue reading

8 bit and 4 bit LCD interfacing with ATtiny

Since my brief journey to controlling LCD display directly with ATtiny2313 I purchased a display with Hitachi HD44780 compatible driver chip. The web is already pretty full of LCD tutorials and libraries, but most seemed to either skip details and rely on external libraries, or were just overly complex. So I decided it wouldn’t hurt to share the rather short (and functionally limited) versions I came up with.

8-bit mode

In 8-bit mode, you will be needing 8 pins for sending or reading a whole byte of data at once, and 3 control lines: enable (EN), register select (RS), and read/write (RW). Basic procedure is to prepare all other lines, and then pulse the enable line high for a short while in which LCD reads your command (when RW is low) or writes data (when RW is high). For control messages, RS line is low, and for writing letters, RS line is high.

I started with ATtiny2313 and used the 8 pins in port B as LCD data lines, and PD4, PD5, and PD6 as RW, RS, and EN, respectively. With such a setup, working write command became:
Continue reading

AVR ATtiny USB Tutorial Part 4

All right. Now that we got the basic USB code working in part 3, it’s time to wrap things up in this tutorial series. This fourth section will explain how to send data from your device to PC and also the other way around. I may later do a fifth part on how to make a USB HID device like a keyboard or mouse, so if you haven’t already, I’d recommend subscribing to the RSS feed to get updates.

Sending data from device to PC

If you look carefully at our command-line client code, you probably noticed that the control messages sent to toggle the led are of type USB_ENDPOINT_IN and we have a 256-byte buffer in place to receive any data the device sends. So far we have not received any data and the return value stored in nBytes has been zero. Let’s change that.
Continue reading

AVR ATtiny USB Tutorial Part 3

This is the third part of my USB tutorial for ATtiny2313 and V-USB library. In the second part we got the breadboard setup more or less covered, and now is the time for actual code! This will most likely be the longest of the three parts, so let’s get started.

Adding V-USB as a part of your project

First, we will download the latest version V-USB library from OBdev. Head to the Downloads-section and get the latest .zip – I got vusb-20120109.zip.

Unzip the archive and copy the usbdrv subfolder to your project folder (the whole folder, not just contents). Go to the subfolder and make a copy of usbconfig-prototype.h with the name usbconfig.h. Locate the #define lines for IO port and port bits and clock rate, and update them as necessary to reflect our configuration where D+ is in PD2 and D- in PD3 and clock rate is 12 MHz:

#define USB_CFG_IOPORTNAME      D
#define USB_CFG_DMINUS_BIT      3
#define USB_CFG_DPLUS_BIT       2
#define USB_CFG_CLOCK_KHZ       12000

Continue reading

arrow Older posts