Posted on Leave a comment

Five way pushbutton latch

As a former hardware designer and embedded programmer I still like a little challenge. I design and build my own devices here are home but sometimes I get asked for a solution to a electronic design problem. When I was working as a designer there was always the challenge of my boss wanting to reduce the hardware, he said if you can fix it in software it will only cost me once, if you fix it in hardware it will cost me on every device. He could drive me crazy when he had been to the golf course and someone had convinced him to buy an even cheaper chip (that was not compatible most of the time) and I had to fix this in software. It created my way of thinking right now, be creative and use as less hardware resources as possible.

Someone asked me for a simple circuit that had five input pushbuttons and five output lines and when a button was pushed the corresponding output line had to go high. This is basically a latch function. There was one restriction, there may only be one output line active at the same time. You could create a circuit with traditional components but you would need a lot of resistors and diodes and transistors or a logical IC to do this. So a microcontroller option seemed the best solution. A PIC chip could do this, but I am not a big PIC fan, I like the AVR chips. My first idea was a ATTiny2313, as I had a few of them. This chip as an internal oscillator and internal pullups so a bare chip could do the job. I wrote some code using PlatformIO and downloaded that into a chip. It works as planned, the design and the code are below, there is also a zip file with the code of the PlatformIO project.

// -----------------------------------------------------
// Read 5 inputs and latch this input to the output
// Only one output can be active at the same time
// PA0 PA1  PD2 PD3 PD4 are inputs
// PB1 PB2 PB3 PB4 PB5  are outputs
// ------------------------------------------------------

#include <Arduino.h>

void setHigh(int prt);

// -----------------------------
// Init hardware
// -----------------------------

void setup() 
{
    PORTA = _BV(PA0) | _BV(PA1);             // Set input + pullup 
    PORTD = _BV(PD2) | _BV(PD3) | _BV(PD4);  // Set input + pullup 
    DDRB = 0xff; // All pins of portB as output
    setHigh(1);
}


// -----------------------------------
// Main loop scan inputs
// -----------------------------------
void loop() 
{
   while (-1) {     
     if (~PINA & 0x02) { 
        setHigh(1);
        continue;    // Prevent two keys at the same time
     } 
     if (~PINA & 0x01) { 
        setHigh(2);
        continue;
     } 
     if (~PIND & 0x04) { 
        setHigh(3);
        continue;
     }     
     if (~PIND & 0x08) { 
        setHigh(4);
        continue;
     }     
     if (~PIND & 0x10) {
        setHigh(5); 
        continue;
     }       
   }
}

// ------------------------------------
// Set one ouput high 1..5
// ------------------------------------
void setHigh(int prt) 
{
   PORTB = 0; // All off
   switch(prt) {
    case 1: PORTB |= 0x20;
            break; 
    case 2: PORTB |= 0x10;
            break; 
    case 3: PORTB |= 0x08;
            break;             
    case 4: PORTB |= 0x04;
            break; 
    case 5: PORTB |= 0x02;
            break; 
   } 
}

Even smaller design

Then my old habit started to come up and I saw the unused pins and thought this is a shame, a ATTiny24A with only 14 pins could do the same. So I went back to the beginning and rewired the breadboard for a ATTiny24A. I created a new project in PlatformIO and reused the old code. This also works, so you can use whatever chip is cheaper, both do the same.  This design and the code are also below, there is also a zip file with the code of the PlatformIO project.  These designs and code are free to use, there is no copyright.  

// -----------------------------------------------------
// Read 5 inputs and latch this input to the output
// Only one output can be active at the same time
// PB0 PB1 PB2 PA7 PA6 are inputs
// PA1 PA2 PA3 PA4 PA5  are outputs
// ------------------------------------------------------

#include <Arduino.h>

void setHigh(int prt);

// -----------------------------
// Init hardware
// -----------------------------

void setup() 
{
    PORTB = _BV(PB0) | _BV(PB1) |_BV(PB2);  // Set input + pullup 
    PORTA = _BV(PA7) | _BV(PA6);  // Set input + pullup 
    DDRA = 0x3f; // All pins of portA as output exept 6 and 7
    setHigh(1);
}


// -----------------------------------
// Main loop scan inputs
// -----------------------------------
void loop() 
{
   while (-1) {     
     if (~PINB & 0x01) { 
        setHigh(1);
        continue;    // Prevent two keys at the same time
     } 
     if (~PINB & 0x02) { 
        setHigh(2);
        continue;
     } 
     if (~PINB & 0x04) { 
        setHigh(3);
        continue;
     }     
     if (~PINA & 0x80) { 
        setHigh(4);
        continue;
     }     
     if (~PINA & 0x40) {
        setHigh(5); 
        continue;
     }       
   }
}

// ------------------------------------
// Set one ouput high 1..5
// ------------------------------------
void setHigh(int prt) 
{
   PORTA &= 0xC0; // All off
   switch(prt) {
    case 1: PORTA |= 0x02;
            break; 
    case 2: PORTA |= 0x04;
            break; 
    case 3: PORTA |= 0x08;
            break;             
    case 4: PORTA |= 0x10;
            break; 
    case 5: PORTA |= 0x20;
            break; 
   } 
}

Arduino Uno based ISP shield

To program the ATTiny24 you will need to have an ISP programmer, I have designed several shields for different AVR processors, this is the shield I designed and build for the ATTiny24.

Have fun using this in your own way or as inspiration, regards, Hein Pragt

Leave a Reply