Just changing this thread as I haven't found an alternative to the original question...
Basically I have the need for a small display that can be attached to the PCB's for basic operations such as count down timer, clock or to check/set a variable using a simple menu.
As always, I want the thing to perform as quickly as possible and the library to have the least possible impact. For example, I can either run it on a UNO or an ATTINY.
A small 4 digit 7 segment display seems to fit the bill nicely. It is cheap, small enough to just about fit in a PCB and simple enough to control that memory footprint is not a major issue.
A number of solutions are available, none of which I think its ideal, so I built my own implementation using a pair of shift registers. Refresh is taken care by polling timer 0 output Compare A interrupt, which should not affect timing or PWM functionality.
The display uses only 3 pins. Its a bit-banged SPI implementation, so should work fine on devices without the SPI/I2C port such as the smaller ATTINY's.
The code:
// SW SPI PIN SETUP
//-----------------------------------------------------------------------------------------------------------
int SS1 = 2; // set slave select 1 pin
int CLK = 3; // set clock pin
int MOUT = 4; // set master out, slave in pin
int i;
//-----------------------------------------------------------------------------------------------------------
// SW SPI TEMP VARIABLES
//-----------------------------------------------------------------------------------------------------------
byte control = 0; // Used to define the digit to print
byte data_byte = 0; // This is the actual data printed on each digit
byte work = 0; // Working byte, used to bit shift data out
// DEFINE OUTPUT POLARITY (Change for common Anode/Cathode displays)
//-----------------------------------------------------------------------------------------------------------
#define DIGIT_ON HIGH
#define DIGIT_OFF LOW
#define SEGMENT_ON HIGH
#define SEGMENT_OFF LOW
void setup() {
// Set up Pins used for SPI Data transmission as digital outputs
pinMode(SS1, OUTPUT); // set CS pin to output
pinMode(CLK, OUTPUT); // set SCK pin to output
pinMode(MOUT, OUTPUT); // set MOSI pin to output
digitalWrite(SS1, HIGH); // hold slave select 1 pin high, so that chip is not selected to begin with
TIMSK0 |= _BV(OCIE0A); // Timer0 compare output interrupt enable (A)
}
void loop()
{
Serial.println((millis()/1000));
//displayNumber(millis()/1000);
}
void displayNumber(int toDisplay)
{
long beginTime = millis();
for(int digit = 4 ; digit > 0 ; digit--)
{
//Turn on a digit for a short amount of time
switch(digit)
{
case 1:
control &= ~_BV(1); // CHIP SELECT - DSPIC DATA, SPI
break;
case 2:
control &= ~_BV(2);
break;
case 3:
control &= ~_BV(3);
break;
case 4:
control &= ~_BV(4);
break;
}
//Turn on the right segments for this digit
lightNumber(toDisplay % 10);
toDisplay /= 10;
//Turn off all segments
lightNumber(10);
control = 0b00011110;
}
}
//Given a number, turns on those segments
//If number == 10, then turn off number
void lightNumber(int numberToDisplay)
{
switch (numberToDisplay){
case 0:
data_byte = 0b11111100;
break;
case 1:
data_byte = 0b01100000;
break;
case 2:
data_byte = 0b11011010;
break;
case 3:
data_byte = 0b11110010;
break;
case 4:
data_byte = 0b01100110;
break;
case 5:
data_byte = 0b10110110;
break;
case 6:
data_byte = 0b10111110;
break;
case 7:
data_byte = 0b11100000;
break;
case 8:
data_byte = 0b11111110;
break;
case 9:
data_byte = 0b11110110;
break;
case 10:
data_byte = 0;
break;
}
// Finally shift the data out to the display
spi_out(SS1, data_byte, control); // send out data to chip 1, pot 0
//delay(2);
}
void spi_transfer(byte working)
{
; // function to actually bit shift the data byte out
for(int i = 1; i <= 8; i++)
{
// setup a loop of 8 iterations, one for each bit
if (working > 127) { // test the most significant bit
digitalWrite (MOUT,HIGH); // if it is a 1 (ie. B1XXXXXXX), set the master out pin high
}
else
{
digitalWrite (MOUT, LOW); // if it is not 1 (ie. B0XXXXXXX), set the master out pin low
}
digitalWrite (CLK,HIGH); // set clock high, the pot IC will read the bit into its register
working = working << 1;
digitalWrite(CLK,LOW); // set clock low, the pot IC will stop reading and prepare for the next iteration (next significant bit
}
}
void spi_out(int SS, byte cmd_byte, byte data_byte)
{
// SPI tranfer out function begins here
digitalWrite (SS, LOW); // set slave select low for a certain chip, defined in the argument in the main loop. selects the chip
work = cmd_byte; // let the work byte equal the cmd_byte, defined in the argument in the main loop
spi_transfer(work); // transfer the work byte, which is equal to the cmd_byte, out using spi
work = data_byte; // let the work byte equal the data for the pot
spi_transfer(work); // transfer the work byte, which is equal to the data for the pot
digitalWrite(SS, HIGH); // set slave select high for a certain chip, defined in the argument in the main loop. deselcts the chip
}
ISR(TIMER0_COMPA_vect) // timer compare interrupt service routine
{
i++;
if (i>5)
{
i=0;
displayNumber(millis()/1000);
}
}
Ill follow up at a later stage with schematics and a PCB