Sunday, April 17, 2011

Shift Registers

My idea for an 8-bit hex decoder discussed in the previous post turns out to have been overcomplicated.  It would've been fun to implement, but was still too complicated.  Recall that I was going to use a PISO shift register for input, an ATTiny85 as the brains, and two SIPO shift registers -- one for each 7-segment display.  Looking around (I can't remember the source), I realized that the output stage didn't need nearly quite so many components.  If I have nine output pins (maybe eight?), I can connect both displays simultaneously, using the same pins, with transistors on their common anode lines to switch between the two.  The idea is that I set the segments on the first display while the second is off, and then vice versa.  Do it fast enough, and the eye thinks they've both been on the whole time.

In order to do this, though, I need 8-9 output pins on the microcontroller which can be devoted to the output stage.  As it happens, the ATTiny2313 should have enough, and is about the size of the ATTiny85 and one of the shift registers.

But enough about that.  I wanted to play with shift registers, even if I wasn't going to use them in the digit decoder.  To do that, I used an ATMega644 to drive a single 7-segment display.  For input, I used four switches connected to a 74HC165N shift register.  Output was via a 74HC565N shift register.  Why shift registers and an ATMega644, which is wildly overpowered for this application, and which could read the switches and drive the 7-segment display directly?  I didn't want to have to worry about microcontroller constraints (RAM size, etc), and wanted to concentrate on the shift registers.


This is the most complicated circuit I've ever breadboarded, and it just about fills up the breadboard.  Everything from the ATMega644 to the left on the lower row is necessary support stuff (from right to left, the MCU, RS232 transceiver, and power switch.  So basically support stuff takes up 1/3 of the board, leaving me the other 2/3.  I'm going to need to switch to the big board soon.  I'm tempted to leave the ATMega644 set up on this one so I don't have to rewire it and the transceiver whenever I want to use it.  At the very least, I'll probably leave it set up until I verify whether I can make the hex decoder work.

Lessons learned (or relearned):
  • Fuses are important.  Not the kind that blow when there's too much current (though they're useful too), but the kind Atmel uses to configure AVR processors.  The first one to bite me was the one that controls the JTAG interface. With it enabled (which it is by default), PC2-PC5 are dedicated to JTAG use.  PC0 and PC1 function normally, which gave me one heck of a time trying to figure out why an early 3-LED circuit (one each on PC0-PC2) would only partially work.
  • The other important fuses are the ones which control the oscillator.  Atmel has a bewildering array of oscillator configuration options, involving 8 of the 19 fuses on the ATMega644.  This AVR fuse calculator was very helpful.
  • To write fuses, invoke avrdude as
    avrdude -p part -U fusename:w:0xvalue:m
  • To read fuses to stdout, invoke it as
    avrdude -p part -U fusename:r:-:h
  • I'd learned about aliasing while watching an EEVblog review of the "budget" Agilent 2000-series oscilloscope, and this time I got to see it in person.  I wanted to verify that the processor was running properly at 16MHz, so I set the CKOUT pin, and ran it through my PCSU1000.  I don't remember which Time/Div setting I was using, but I was seeing a stable output sine wave at about 1kHz, rather than 16MHz.  Hilarity ensued until I remembered Dave's mention of aliasing, at which point I decreased the Time/Div setting.  Low and behold, a 16MHz wave appeared.  So that was exciting.
  • You don't use the same variable for writing AVR ports as you do for reading them.  PORTn for output, PINn for reading.   Reading from PORTn, expecting to get input values, will only lead to sadness and dismay.

1 comment:

  1. If you connect the common anode to the MCU and PWM it really fast in software, you can omit the current limiting resistors. It requires more code but saves you 7-8 components per display (unless you accidentally burn out the LED segments, that is). See this project for reference: