Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- * FourDigitSevenSegmentDisplayDriver.c
- *
- * Created: 1/31/2012 1:09:17 AM
- * Author: grist.carrigafoyl
- Code to turn an ATtiny2313 into a 4 digit 7 segment display driver. This will
- allow offloading multiplexing a typical LED display to a slave chip and
- let the main CPU get on with whatever it's doing. The driver displays
- whatever is in its data register until it receives new data over the
- serial lines.
- Employs a 5 byte protocol with the first byte containing flags that control
- the colon and degrees indication and also how the data is displayed
- and the other 4 bytes contain the data to be displayed.
- Using Don Blake's translation of the Atmel I2C (TWI) library.
- First byte
- First 4 bits are format related
- 1 (128) - bit 1 of format
- 2 (64) - bit 2 of format
- 3 (32) - bit 1 of format params
- 4 (16) - bit 2 of format params
- Second 4 bits are display option related (not implemented for now)
- 5 (8) - flashing (not implemented)
- 6 (4) - scrolling (not implemented)
- 7 (2) - bit 1 of display option params
- 8 (1) - bit 2 of display option params
- */
- #define F_CPU 8000000UL // 8Mhz
- #define NUM_DIGITS 4
- #define NUM_SEGMENTS 8 // a 7 segment display has 8 segments. #8 is the decimal point
- #define NUM_BYTES_IN_PROTOCOL 5 // how many bytes to read at a time
- #include <avr/io.h>
- #include <util/delay.h>
- #include <avr/interrupt.h> // for I2C
- #include "usiTwiSlave.h" // Don Blake's library
- // The TWI address for this slave device
- const uint8_t TWI_SLAVE_ADDRESS = 0x01;
- // Constants for option byte bitmapping. First 4 bits are for the display format
- const uint8_t FORMAT_MASK = 0b11000000;
- const uint8_t FORMAT_OPTION_MASK = 0b00110000;
- // RAW format masks
- const uint8_t FORMAT_RAW = 0b00000000; // Param bits are colon & apostrophe
- const uint8_t RAW_OPTION_COLON = 0b00100000;
- const uint8_t RAW_OPTION_APOSTROPHE = 0b00010000;
- // TIME format masks
- const uint8_t FORMAT_TIME = 0b10000000; // (could have param for 24 hr? indicated by dot in pos 1)
- const uint8_t TIME_OPTION_HHMM = 0b00100000;
- const uint8_t TIME_OPTION_MMSS = 0b00010000;
- const uint8_t TIME_OPTION_SECONDS = 0b00110000;
- // DEGREES format masks
- const uint8_t FORMAT_DEGREES = 0b11000000; // Param bits are point position indicator, 0 or 1 are off, only positions 2 & 3 are valid)
- const uint8_t DEGREES_DOT_POS_MASK = 0b00110000;
- // DECIMAL format masks
- const uint8_t FORMAT_DECIMAL = 0b01000000; // Param bits are point postion indicator 0 is off, 123 count from right)
- const uint8_t DECIMAL_DOT_POS_MASK = 0b00110000;
- // Now the display options in the last 4 bits. Not implemented as yet.
- const uint8_t OPTION_FLASHING = 0b00001000; // delay as 2 bit param. Not implemented yet
- const uint8_t OPTION_SCROLLING = 0b00000100; // 2 bit param for direction. Not implemented yet
- const uint8_t OPTION_PARAM0 = 0b00000000;
- const uint8_t OPTION_PARAM1 = 0b00010000;
- const uint8_t OPTION_PARAM2 = 0b00100000;
- const uint8_t OPTION_PARAM3 = 0b00110000;
- // Number bitmaps. Which LEDs to light up to represent each digit
- const uint8_t number_maps[10] = {
- //abcdefgp - 1 for on, 0 for off.
- 0b11111100, // 0
- 0b01100000, // 1
- 0b11011010, // 2
- 0b11110010, // 3
- 0b01100110, // 4
- 0b10110110, // 5
- 0b10111110, // 6
- 0b11100000, // 7
- 0b11111110, // 8
- 0b11110110, // 9
- };
- const uint8_t PATTERN_c = 0b00011010; // lower case 'c' for degrees display
- // Segment to pin mapping.
- enum SEGMENT_PINS {
- seg_a = _BV(PD0),
- seg_b = _BV(PD1),
- seg_c = _BV(PB6),
- seg_d = _BV(PB4),
- seg_e = _BV(PB3),
- seg_f = _BV(PB2),
- seg_g = _BV(PB1),
- seg_dp = _BV(PB0)
- };
- // Digit to pin mapping.
- enum DIGIT_PINS {
- d1 = _BV(PD3),
- d2 = _BV(PD4),
- d3 = _BV(PD5),
- d4 = _BV(PD6)
- };
- // The colon and degree indicator LEDs
- const uint8_t COLON_PIN = _BV(PA0);
- const uint8_t DEG_PIN = _BV(PA1); // degrees indicator (apostrophe)
- // Having a delay between displaying segments helps the persistence of vision and makes the segments brighter.
- // Much larger than this you will see noticeable flickering, much lower and you get dimmed segments.
- const int POV_DELAY = 5; // ms delay for persistence of vision
- // Digit and segment pins
- uint8_t digits[4] = {d1,d2,d3,d4};
- // Segment pins are split over 2 ports as I2C needs 2 pins on PORTB
- uint8_t portb_segment_mask = (seg_c | seg_d | seg_e | seg_f | seg_g | seg_dp);
- uint8_t portd_segment_mask = (seg_a | seg_b);
- volatile uint8_t data[NUM_BYTES_IN_PROTOCOL] = {0,255,255,255,255}; // this will hold the data to be displayed
- // Function prototypes
- void displayData();
- void showPattern(uint8_t pattern);
- int main(void)
- {
- // Set the pin modes for output
- DDRA |= (COLON_PIN | DEG_PIN);
- DDRB |= portb_segment_mask; // all pins except SDA & SCL (PB5 & 7) on PortB are output
- DDRD |= (d1 | d2 | d3 | d4 | portd_segment_mask ); // the digit selector pins & 2 of the segment pins
- // Initialise the I2C interface
- usiTwiSlaveInit(TWI_SLAVE_ADDRESS);
- // Enable global interrupts (required for I2C)
- sei();
- // main loop
- for(;;) { // forever
- // Check to see if there's data to read in
- if (usiTwiDataInReceiveBuffer()) {
- // get some bytes
- for (int i=0;i<NUM_BYTES_IN_PROTOCOL;i++) {
- data[i] = usiTwiReceiveByte();
- }
- }
- // show the current data
- displayData();
- }
- }
- //----------------------------------------------------------------------------
- // Functions
- //----------------------------------------------------------------------------
- void displayData() {
- // show the data on the display
- // Flags for various display options
- bool show_colon = false;
- bool show_apostrophe = false;
- uint8_t dot_postion = 3;
- uint8_t pattern[4] = {0,0,0,0}; // will hold the raw bitmap of the pattern to be shown on the display
- int temp;
- uint8_t opt_byte = data[0]; // the options bitmapped flag
- // set up the display options
- if ((opt_byte & FORMAT_MASK) == FORMAT_RAW) { // No option bits set so it's RAW format
- // RAW format setup
- if ((opt_byte & FORMAT_OPTION_MASK) == RAW_OPTION_COLON) { show_colon = true; }
- if ((opt_byte & FORMAT_OPTION_MASK) == RAW_OPTION_APOSTROPHE) { show_apostrophe = true; }
- // now copy the raw patterns into our array
- for (int d=0 ; d<NUM_DIGITS; d++) {
- pattern[d] = data[d+1];
- }
- } else if ((opt_byte & FORMAT_MASK) == FORMAT_TIME) {
- // Time display setup. Doesn't use options bits yet
- // change this to take time in seconds. auto adjust units (hh:mm or mm:ss)
- // use dp to show hh:mm, try all, see how it looks
- show_colon = true;
- // ignoring hour & 10th sec bytes for now, just min/sec (bytes 2 & 3)
- temp = data[2];
- pattern[0] = number_maps[temp/10];
- pattern[1] = number_maps[temp % 10];
- temp = data[3];
- pattern[2] = number_maps[temp/10];
- pattern[3] = number_maps[temp % 10];
- } else if ((opt_byte & FORMAT_MASK) == FORMAT_DEGREES) {
- // Temperature display setup
- show_apostrophe = true;
- pattern[3] = PATTERN_c;
- // only 1 dot position is valid
- if ((opt_byte & DEGREES_DOT_POS_MASK) == 0b00100000) {
- dot_postion = 1; // actual dot postions are numbered left to right
- }
- // use all 4 bytes, but current display can only show 999 degs max
- temp += data[1] * 16777216;
- temp += data[2] * 65536;
- temp += data[3] * 256;
- temp += data[4];
- temp %= 1000;
- // convert the resulting integer to single digit patterns for display
- pattern[0] = number_maps[temp/100];
- temp %= 100;
- pattern[1] = number_maps[temp/10];
- temp %= 10;
- pattern[2] = number_maps[temp];
- } else if ((opt_byte & FORMAT_MASK) == FORMAT_DECIMAL) {
- // A decimal digit
- // Get the number of decimal places and convert it to the dot position
- dot_postion = 3 - ((opt_byte & DECIMAL_DOT_POS_MASK) >> 4);
- // Convert the 4 bytes to an integer, but current display can only show 9999 max
- temp += data[1] * 16777216;
- temp += data[2] * 65536;
- temp += data[3] * 256;
- temp += data[4];
- temp %= 10000;
- // convert the resulting integer to single digit patterns for display
- pattern[0] = number_maps[temp/1000];
- temp %= 1000;
- pattern[1] = number_maps[temp/100];
- temp %= 100;
- pattern[2] = number_maps[temp/10];
- temp %= 10;
- pattern[3] = number_maps[temp];
- }
- // Time to display what we've got
- // set the colon and apostrophe as required
- if (show_colon == true) { PORTA |= COLON_PIN; } else { PORTA &= ~COLON_PIN; }
- if (show_apostrophe == true) { PORTA |= DEG_PIN; } else { PORTA &= ~DEG_PIN; }
- // // Now show the pattern.
- for (int d=0 ; d<NUM_DIGITS ; d++) {
- // Choose the digit to display by setting it's pin HIGH and
- // all the other pins LOW.
- PORTD &= ~( d1 | d2 | d3 | d4);
- PORTD |= digits[d];
- // Actual dots are numbered left to right (0-3)
- if (dot_postion != 3 && d == dot_postion) {
- pattern[d] |= 0b00000001; // turn on the dot for this segment
- }
- showPattern(pattern[d]);//
- }
- }
- //----------------------------------------------------------------------------
- void showPattern(uint8_t pattern) {
- // show the current pattern on the currently selected digit
- // First set all the digit pins HIGH to turn them off so the
- // previous digit doesn't get ghosted onto the new segment
- // Segments a & b are on PORTD, the rest are on PORTB
- PORTD |= (portd_segment_mask);
- PORTB |= (portb_segment_mask);
- // Have to manipulate the pins one at a time so as not to interfere with I2C
- // PORTD segments
- if ((pattern & 128) == 128) { PORTD &= ~seg_a; } else { PORTD |= seg_a; }
- if ((pattern & 64) == 64) { PORTD &= ~seg_b; } else { PORTD |= seg_b; }
- // PORTB segments
- if ((pattern & 32) == 32) { PORTB &= ~seg_c; } else { PORTB |= seg_c; }
- if ((pattern & 16) == 16) { PORTB &= ~seg_d; } else { PORTB |= seg_d; }
- if ((pattern & 8) == 8) { PORTB &= ~seg_e; } else { PORTB |= seg_e; }
- if ((pattern & 4) == 4) { PORTB &= ~seg_f; } else { PORTB |= seg_f; }
- if ((pattern & 2) == 2) { PORTB &= ~seg_g; } else { PORTB |= seg_g; }
- if ((pattern & 1) == 1) { PORTB &= ~seg_dp; } else { PORTB |= seg_dp; }
- // Delay so the image stays on the retina
- _delay_ms(POV_DELAY);
- }
- //----------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement