Step two: add latches

Even though I use a big 40 pin PIC for my experiments I decided to try how sharing output pins for multiple purposes works. To do that I use two 74HCT573 (PDF) octal latches. The goal is to drive 16 outputs from 10 pins. If you add one more octal latch, it only costs one more pin to drive 8 more outputs. So, with 16 pins and 8 octal latches, you could come to 64 outputs.

I also added an output stage with a reed relay. My final goal is to make a variation on the looper project that can be found at jimkim.de.


The schema on my breadboard now looks like this:

On the software side I tried something new too: an interrupt handler. From the first version I also changed to use port D instead of port C since a future step will be to use the USART and that uses two pins of port C. Anyway, the code now looks like this:

// First PIC experiments by Bart van der Velden
// Based on tutorials written by Devlin Thyne and gooligum.com.au
//
// This program increments a counter every 500 ms and shows puts the
// binary value on one output and the binary value with all bits
// inverted on another output. Utterly useless, but it shows how to
// use octal latches to drive more outputs with not too many pins.
//
// Port D is used as output port connected to two octal latches.
// RC4 and RC5 are used to select the octal latch to output to.
//
// Delay routines by Tyler Montbriand at burningsmell.org, but not
// needed in this example.
//
// The timer for the interrupt is set as explained by the tutorials
// at www.gooligum.com.au
//
//
//
// To compile:
// sdcc -mpic14 -p16f887 blink.c
//
// To program the chip using pk2cmd:
// pk2cmd -M -T -R -PPIC16f887 -Fblink.hex

#include "pic16f887.h"

#define KHZ 20000L
#define INSTANTIATE_DELAY
#include "tsmdelay.h"

//Set the configuration words:
Uint16 __at _CONFIG1 configWord1 =
	_DEBUG_OFF & // In circuit debugging off (I don't have an ICD 2)
	_LVP_OFF &   // Low voltage programming off
	_FCMEN_ON &  // Fail-safe clock monitor is enabled
	_IESO_ON &   // Internal/external switchover mode is enabled
	_BOR_ON &    // Brown-out reset enabled
	_CPD_OFF &   // Data memory code protection is disabled
	_CP_OFF &    // Program memory code protection is disabled
	_MCLRE_ON &  // MCLR pin is MCLR (not a digital input)
	_PWRTE_ON &  // Power-up timer is disabled
	_WDT_OFF &   // Watchdog timer is disabled
	_HS_OSC;     // External high speed crystal on OSC1 and OSC2

// No write protection and brown-out reset at 4.0V
Uint16 __at _CONFIG2 configWord2 = 0x3fff;

// Setup variables
Uint8 sPortC = 0; // shadow variable for PORTC
Uint8 sPortD = 0; // shadow variable for PORTD

// Set the output on the first octal latch
void SetLeds1()
{
	sPortC |= 0x20;    // Enable latch on D0;
	PORTC = sPortC;

	PORTD = sPortD;    // Set output on PORTC

	sPortC &= 0xDF;    // Disable latch on D0;
	PORTC = sPortC;
}

// Set the output on the second octal latch
void SetLeds2()
{
	Uint8 inv = sPortD ^ 0xFF; // Invert the data to write to PORTC

	sPortC |= 0x10;    // Enable latch on D0;
	PORTC = sPortC;

	PORTD = inv;       // Set output on PORTC

	sPortC &= 0xEF;    // Disable latch on D0;
	PORTC = sPortC;
}

void isr(void) __interrupt
{
	// Handle Timer0 interrupt
	static Uint16 tmr0Cnt = 0; // counts Timer0 overflows

	// Now make the Timer0 interrupt fire every 250 cycles, which
	// is every 50 us with my 20MHz oscillator. See details at
	// http://gooligum.com.au/tutorials/midrange/PIC_Mid_C_3.pdf
	// around page 8.
	TMR0 += 256-250+3;
	T0IF = 0;

	++tmr0Cnt; // increment interrupt count (every 50 us)
	if (tmr0Cnt == 500000/50) // every 0.5 sec
	{
		tmr0Cnt = 0;
		sPortD++;
		SetLeds1();
		SetLeds2();
	}
}

void main(void)
{
	// Set PORTC and PORTD to all outputs
	TRISC = 0x00;
	TRISD = 0x00;

	// Setup Timer0
	OPTION_REG = 0b11011111;
	             //--0-----  timer mode (TOCS = 0)
	             //----1---  no prescaler (assigned to WDT, PSA = 1)

	INTCON = 0;	// Clear interrupt flag bits.
	GIE = 1;	// Enable all interrupts.

	T0IE = 1;	// Set Timer 0 to 0.
	TMR0 = 0;	// Enable peripheral interrupts.

	PORTC = 0;
	PORTD = 0;

	// Loop forever, everything relevant is in the interrupt routine
	while (1)
	{
	}
}

And everything seems to work. Of course I made mistakes in the wiring again and also whilst programming, but I only show the end result here.

If all goes well I receive some new components for a 4 digit 7 segment LED display today, so hooking all that up will be the next step.