If you are still interested, I have just been making an arduino timelapse camera controller, whic required a seven segment display. I thought I would share the code if you want to see it.
This used a timer interrupt to refresh the display at i think a refresh rate of 5kHz. I have stripped the code down to just the display portion here:
/*
Created by Thomas Carpenter 2012
=====================================================
Things to note:
- millis(); will be highly inaccurate due to the frequent interrupts for the screen.
> millisecs; should be used instead - works exactly the same, but unaffected by screen
=====================================================
- strn2Disp(char string); is used to print a text string to the display.
> strn2Disp("HELLO"); would display HELLO on the screen, depending of the number of digits (eg, 3 digits would display "HEL")
=====================================================
- num2Disp(int number, byte decimalPoint); is used to print a positive or negative number of the screen.
> num2Disp(-100); would print [-][1][0][0] - Note, no decimal point
> num2Disp(-100,0); would print [-][1][0][0.] - Note, decimal point after last digit
> num2Disp(1234); would print [1][2][3][4]
> num2Disp(100,1); would print [0][1][0.][0] - Note the number is considered as 10ths
> num2Disp(100,2); would print [0][1.][0][0] - Note the number is considered as 100ths
> num2Disp(1234,2); would print [1][2.][3][4] - Note the number is considered as 100ths
> If the number is too big to be displayed, e.g. trying to display 1234 on a 3 digit display, it is converted to the maximum value the display can take,
so in this case, 1234 would be displayed as 999 on a 3 digit display.
=====================================================
- displayedChars[2][DIGITS]; contains what is to be printed to the screen. This can be directly editied
> displayedChars[0][3] = 'A';
displayedChars[1][3] = 0; would set the third digit to [A]
> displayedChars[0][2] = 'C';
displayedChars[1][2] = 1; would set the second digit to [C.] - Note the decimal point/full stop
> In otherwords, displayedChars[0][x] contains the xth character to be printed, and
displayedChars[1][x] controls whether the xth decimal point is one (multiple points can be on)
=====================================================
*/
//Change these too suit==================================================================================================================================
//Number of display digits
#define DIGITS 3
//use "#define COMAN" for common Anode, or "#define COMCATH" for common Cathodes
#define COMAN
//Display Pins
const byte segmentPins[8] = {9,11,17,13,12,10,16,18}; //{a,b,c,d,e,f,g,DP};
const byte commonPins[DIGITS] = {2,1,3}; //{Digit '0',Digit '1',Digit '2',....,Digit 'n-1'}; - Add one for each digit. Example Display: [n-1]...[2][1][0]
//=======================================================================================================================================================
//Dont Change these!=====================================
volatile unsigned long millisecs; //millis() is ruined by the screen refresh interrupt, so creating my own
#if defined COMAN
#define OFF LOW
#define ON HIGH
#elif defined COMCATH
#define OFF HIGH
#define ON LOW
#else
//If neither defined, it defaults to common anode
#define COMAN
#define OFF LOW
#define ON HIGH
#endif
#define MAPSIZE 40
void num2Disp(int num, byte decimalPoint = DIGITS);
void strn2Disp(char str[]);
void updateDisplay();
void configureTimer();
const int maxPositive = pow(10,DIGITS) - 1;
const int maxNegative = pow(10,DIGITS - 1) - 1;
char displayedChars[2][DIGITS];
char asciiNumbers[10] = {'0','1','2','3','4','5','6','7','8','9'};
//=======================================================
//You can add custom characters here, just increase 'custom' to how many custom characters there are,
//and add the character to the end of the list.
//Note: a,b,c,d,e,f,g are the segments, where 1 = ON.
// ID is the ASCII character it represents.
const char custom = 0;
const char characterMap[MAPSIZE + custom][8] = {
// a b c d e f g ID
{1,1,1,1,1,1,0,'0'},
{0,1,1,0,0,0,0,'1'},
{1,1,0,1,1,0,1,'2'},
{1,1,1,1,0,0,1,'3'},
{0,1,1,0,0,1,1,'4'},
{1,0,1,1,0,1,1,'5'},
{1,0,1,1,1,1,1,'6'},
{1,1,1,0,0,0,0,'7'},
{1,1,1,1,1,1,1,'8'},
{1,1,1,1,0,1,1,'9'},
{0,0,0,0,0,0,0,' '},
{0,0,0,0,0,0,0,'.'},
{0,0,0,0,0,0,1,'-'},
{0,0,0,1,0,0,1,'='},
{1,1,1,0,1,1,1,'A'},
{1,1,1,1,1,1,1,'B'},
{0,0,0,1,1,0,1,'C'},
{0,1,1,1,1,0,1,'D'},
{1,0,0,1,1,1,1,'E'},
{1,0,0,0,1,1,1,'F'},
{1,0,1,1,1,1,0,'G'},
{0,0,1,0,1,1,1,'H'},
{0,0,1,0,0,0,0,'I'},
{0,0,1,1,0,0,0,'J'},
{0,0,0,0,0,0,0,'K'},
{0,0,0,1,1,1,0,'L'},
{0,0,0,0,0,0,0,'M'},
{0,0,1,0,1,0,1,'N'},
{0,0,1,1,1,0,1,'O'},
{1,1,0,0,1,1,1,'P'},
{1,1,1,0,0,1,1,'Q'},
{0,0,0,0,1,0,1,'R'},
{1,0,1,1,0,1,1,'S'},
{0,0,0,1,1,1,1,'T'},
{0,0,1,1,1,0,0,'U'},
{0,0,0,0,0,0,0,'V'},
{0,0,0,0,0,0,0,'W'},
{0,0,0,0,0,0,0,'X'},
{0,1,1,1,0,1,1,'Y'},
{1,1,0,1,1,0,1,'Z'}
};
//Main Program--------------------------------------------------------------------------------
void setup() {
//Display (Dont change)=================================================
for(byte i = 0;i < 8;i++){
pinMode(segmentPins[i],OUTPUT);
}
for(byte i = 0;i < DIGITS;i++){
pinMode(commonPins[i],OUTPUT);
digitalWrite(commonPins[i],OFF); //Digit off
}
for(byte i = 0;i < DIGITS;i++){
displayedChars[0][i] = ' '; //Display is blank to begin with
displayedChars[1][i] = 0; //No Decimal Point
}
configureTimer();
//======================================================================
//rest of setup here
}
void loop() {
//main program
}
//--------------------------------------------------------------------------------------------
//Display--------------------------------------------------------------------------------
void strn2Disp(char str[]){
char string[DIGITS]; //Create input array
strncpy(string,str,DIGITS); //Truncate or pad the input string
char *input = string; //Pointer to the input string
char *output = displayedChars[0] + DIGITS; //Pointer to the last character in display string
for(char i = 0; i < DIGITS;i++){
*--output=*input++; //Copy string to display, reversing it as digits are in reverse order
}
for(char i = DIGITS - 1;i >= 0;i--){
if(displayedChars[0][i] == '.'){
displayedChars[1][i] = 1;
} else {
displayedChars[1][i] = 0;
}
}
}
void num2Disp(int num, byte decimalPoint){
byte sign = 0;
if(num > maxPositive){
num = maxPositive; //Max displayable number
} else if(num < 0){
sign = 1;
displayedChars[0][DIGITS - 1] = '-'; //Minus sign as most significant
if(num < -maxNegative){
num = maxNegative; //If there is a sign, then |max| number is 999
} else {
num = -num; //Switch to positive as sign taken into account
}
}
for(byte digit = 0;digit < (DIGITS - sign);digit++){
//Convert the remainder when divided by 10 into ASCII and save it to the digit
byte digitNumber = num % 10;
if(decimalPoint == digit){
displayedChars[1][digit] = 1; //decimal point on this one
} else {
displayedChars[1][digit] = 0; //No decimal point
}
displayedChars[0][digit] = asciiNumbers[digitNumber];
num /= 10; //Integer divide the number by 10 to reveal next digit
}
}
void updateDisplay(){
for(byte digit = 0;digit < DIGITS;digit++){ //Count through each display digit
byte ID;
for(ID = 0;ID < (MAPSIZE+custom);ID++){ //lookup character ID
if(characterMap[ID][7] == displayedChars[0][digit]){
break; //ID found, so break loop early to save time
}
}
if(ID == (MAPSIZE+custom)){
ID = 10; //blank digit as non printable character
}
for(byte segment = 0;segment < 7;segment++){
#if defined COMAN
digitalWrite(segmentPins[segment],!characterMap[ID][segment]);
#elif defined COMCATH
digitalWrite(segmentPins[segment],characterMap[ID][segment]);
#endif
}
#if defined COMAN
digitalWrite(segmentPins[7],!displayedChars[1][digit]);
#elif defined COMCATH
digitalWrite(segmentPins[7],displayedChars[1][digit]);
#endif
digitalWrite(commonPins[digit],ON); //digit on
for(byte j = 0;j < 100;j++){
//leave the digit on for a little bit
}
digitalWrite(commonPins[digit],OFF); //digit off
}
}
//--------------------------------------------------------------------------------------------
//Timer Interrupt-----------------------------------------------------------------------------
/*Enable the the timer interrupt to be used for refreshing the screen at 1ms intervals*/
void configureTimer(){
TIMSK2 &= ~(1<<TOIE2); //disable timer so it can be configured
//set to normal counting mode
TCCR2A &= ~((1<<WGM21) | (1<<WGM20));
TCCR2B &= ~(1<<WGM22);
//Clock source is system clock
ASSR &= ~(1<<AS2);
//Disable compare interrupt (only interested in overflow)
TIMSK2 &= ~(1<<OCIE2A);
//Set prescaler to F_CPU/64
TCCR2B |= (1<<CS22); //1
TCCR2B &= ~(1<<CS21);//0
TCCR2B &= ~(1<<CS20);//0
//This equates to 0.2ms exactly per overflow
TCNT2 = 206;
//Enable timer and overflow interrupt
TIMSK2 |= (1<<TOIE2);
millisecs = 0;
}
/*Timer Interrupt Vector (1/5th millisecond)*/
ISR(TIMER2_OVF_vect) {
static byte fifths = 0;
TCNT2 = 206; //reset timer straight away to avoid compounding errors
fifths++; //another fifth of a millisecond passed
if(fifths == 5){
fifths = 0;
millisecs++; //one millisecond has passed
}
updateDisplay(); //Update Display
}
//--------------------------------------------------------------------------------------------