Advertisement
grist

ATtiny2313 I2C Slave Working

Mar 5th, 2012
2,763
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.07 KB | None | 0 0
  1. /*
  2.  * FourDigitSevenSegmentDisplayDriver.c
  3.  *
  4.  * Created: 1/31/2012 1:09:17 AM
  5.  *  Author: grist.carrigafoyl
  6.  
  7. Code to turn an ATtiny2313 into a 4 digit 7 segment display driver. This will
  8. allow offloading multiplexing a typical LED display to a slave chip and
  9. let the main CPU get on with whatever it's doing. The driver displays
  10. whatever is in its data register until it receives new data over the
  11. serial lines.
  12.  
  13. Employs a 5 byte protocol with the first byte containing flags that control
  14. the colon and degrees indication and also how the data is displayed
  15. and the other 4 bytes contain the data to be displayed.
  16.  
  17. Using Don Blake's translation of the Atmel I2C (TWI) library.
  18.  
  19. First byte
  20. First 4 bits are format related
  21. 1 (128) - bit 1 of format
  22. 2 (64) - bit 2 of format
  23. 3 (32) - bit 1 of format params
  24. 4 (16) - bit 2 of format params
  25. Second 4 bits are display option related (not implemented for now)
  26. 5 (8) - flashing (not implemented)
  27. 6 (4) - scrolling (not implemented)
  28. 7 (2) - bit 1 of display option params
  29. 8 (1) - bit 2 of display option params
  30.  
  31. */
  32.  
  33. #define F_CPU 8000000UL  //  8Mhz
  34.  
  35. #define NUM_DIGITS 4
  36. #define NUM_SEGMENTS 8 // a 7 segment display has 8 segments. #8 is the decimal point
  37. #define NUM_BYTES_IN_PROTOCOL 5 // how many bytes to read at a time
  38.  
  39. #include <avr/io.h>
  40. #include <util/delay.h>
  41. #include <avr/interrupt.h> // for I2C
  42.  
  43. #include "usiTwiSlave.h" // Don Blake's library
  44.  
  45. // The TWI address for this slave device
  46. const uint8_t TWI_SLAVE_ADDRESS = 0x01;
  47.  
  48. // Constants for option byte bitmapping. First 4 bits are for the display format
  49. const uint8_t FORMAT_MASK =     0b11000000;
  50. const uint8_t FORMAT_OPTION_MASK = 0b00110000;
  51. // RAW format masks
  52. const uint8_t FORMAT_RAW =      0b00000000; // Param bits are colon & apostrophe
  53. const uint8_t RAW_OPTION_COLON = 0b00100000;
  54. const uint8_t RAW_OPTION_APOSTROPHE = 0b00010000;
  55. // TIME format masks
  56. const uint8_t FORMAT_TIME =     0b10000000; // (could have param for 24 hr? indicated by dot in pos 1)
  57. const uint8_t TIME_OPTION_HHMM = 0b00100000;
  58. const uint8_t TIME_OPTION_MMSS = 0b00010000;
  59. const uint8_t TIME_OPTION_SECONDS = 0b00110000;
  60. // DEGREES format masks
  61. const uint8_t FORMAT_DEGREES =  0b11000000; // Param bits are point position indicator, 0 or 1 are off, only positions 2 & 3 are valid)
  62. const uint8_t DEGREES_DOT_POS_MASK = 0b00110000;
  63. // DECIMAL format masks
  64. const uint8_t FORMAT_DECIMAL =  0b01000000; // Param bits are point postion indicator 0 is off, 123 count from right)
  65. const uint8_t DECIMAL_DOT_POS_MASK = 0b00110000;
  66.  
  67. // Now the display options in the last 4 bits. Not implemented as yet.
  68. const uint8_t OPTION_FLASHING = 0b00001000; // delay as 2 bit param. Not implemented yet
  69. const uint8_t OPTION_SCROLLING = 0b00000100; // 2 bit param for direction. Not implemented yet
  70. const uint8_t OPTION_PARAM0 = 0b00000000;
  71. const uint8_t OPTION_PARAM1 = 0b00010000;
  72. const uint8_t OPTION_PARAM2 = 0b00100000;
  73. const uint8_t OPTION_PARAM3 = 0b00110000;
  74.  
  75. // Number bitmaps. Which LEDs to light up to represent each digit
  76. const uint8_t number_maps[10] = {
  77.     //abcdefgp - 1 for on, 0 for off.
  78.     0b11111100, // 0
  79.     0b01100000, // 1
  80.     0b11011010, // 2
  81.     0b11110010, // 3
  82.     0b01100110, // 4
  83.     0b10110110, // 5
  84.     0b10111110, // 6
  85.     0b11100000, // 7
  86.     0b11111110, // 8
  87.     0b11110110,  // 9
  88. };
  89. const uint8_t PATTERN_c = 0b00011010; // lower case 'c' for degrees display
  90.  
  91.  
  92. // Segment to pin mapping.
  93. enum SEGMENT_PINS {
  94.     seg_a = _BV(PD0),
  95.     seg_b = _BV(PD1),
  96.     seg_c = _BV(PB6),
  97.     seg_d = _BV(PB4),
  98.     seg_e = _BV(PB3),
  99.     seg_f = _BV(PB2),
  100.     seg_g = _BV(PB1),
  101.     seg_dp = _BV(PB0)
  102. };
  103. // Digit to pin mapping.
  104. enum DIGIT_PINS {
  105.     d1 = _BV(PD3),
  106.     d2 = _BV(PD4),
  107.     d3 = _BV(PD5),
  108.     d4 = _BV(PD6)
  109. };
  110.  
  111. // The colon and degree indicator LEDs
  112. const uint8_t COLON_PIN = _BV(PA0);
  113. const uint8_t DEG_PIN = _BV(PA1); // degrees indicator (apostrophe)
  114.  
  115. // Having a delay between displaying segments helps the persistence of vision and makes the segments brighter.
  116. // Much larger than this you will see noticeable flickering, much lower and you get dimmed segments.
  117. const int POV_DELAY = 5; // ms delay for persistence of vision
  118.  
  119. // Digit and segment pins
  120. uint8_t digits[4] = {d1,d2,d3,d4};
  121. // Segment pins are split over 2 ports as I2C needs 2 pins on PORTB
  122. uint8_t portb_segment_mask = (seg_c | seg_d | seg_e | seg_f | seg_g | seg_dp);
  123. uint8_t portd_segment_mask = (seg_a | seg_b);
  124. volatile uint8_t data[NUM_BYTES_IN_PROTOCOL] = {0,255,255,255,255}; // this will hold the data to be displayed
  125.  
  126. // Function prototypes
  127. void displayData();
  128. void showPattern(uint8_t pattern);
  129.  
  130. int main(void)
  131. {
  132.     // Set the pin modes for output
  133.     DDRA |= (COLON_PIN | DEG_PIN);
  134.     DDRB |= portb_segment_mask; // all pins except SDA & SCL (PB5 & 7) on PortB are output
  135.     DDRD |= (d1 | d2 | d3 | d4 | portd_segment_mask );  // the digit selector pins & 2 of the segment pins
  136.    
  137.     // Initialise the I2C interface
  138.     usiTwiSlaveInit(TWI_SLAVE_ADDRESS);
  139.     // Enable global interrupts (required for I2C)
  140.     sei();
  141.  
  142.     // main loop
  143.     for(;;) { // forever
  144.         // Check to see if there's data to read in
  145.         if (usiTwiDataInReceiveBuffer()) {
  146.             // get some bytes
  147.             for (int i=0;i<NUM_BYTES_IN_PROTOCOL;i++) {
  148.                 data[i] = usiTwiReceiveByte();
  149.             }
  150.         }
  151.         // show the current data
  152.         displayData();  
  153.     }
  154. }
  155.  
  156. //----------------------------------------------------------------------------
  157. // Functions
  158. //----------------------------------------------------------------------------
  159. void displayData() {
  160.     // show the data on the display
  161.    
  162.     // Flags for various display options
  163.     bool show_colon = false;
  164.     bool show_apostrophe = false;
  165.     uint8_t dot_postion = 3;
  166.    
  167.     uint8_t pattern[4] = {0,0,0,0};  // will hold the raw bitmap of the pattern to be shown on the display
  168.     int temp;
  169.  
  170.     uint8_t opt_byte = data[0];  // the options bitmapped flag
  171.    
  172.     // set up the display options
  173.     if ((opt_byte & FORMAT_MASK) == FORMAT_RAW) { // No option bits set so it's RAW format
  174.         // RAW format setup
  175.         if ((opt_byte & FORMAT_OPTION_MASK) == RAW_OPTION_COLON) { show_colon = true; }
  176.         if ((opt_byte & FORMAT_OPTION_MASK) == RAW_OPTION_APOSTROPHE) { show_apostrophe = true; }
  177.         // now copy the raw patterns into our array
  178.         for (int d=0 ; d<NUM_DIGITS; d++) {
  179.             pattern[d] = data[d+1];
  180.         }
  181.     } else if ((opt_byte & FORMAT_MASK) == FORMAT_TIME) {
  182.         // Time display setup. Doesn't use options bits yet
  183.         // change this to take time in seconds. auto adjust units (hh:mm or mm:ss)
  184.         // use dp to show hh:mm, try all, see how it looks
  185.         show_colon = true;
  186.         // ignoring hour & 10th sec bytes for now, just min/sec (bytes 2 & 3)
  187.         temp = data[2];
  188.         pattern[0] = number_maps[temp/10];
  189.         pattern[1] = number_maps[temp % 10];
  190.         temp = data[3];
  191.         pattern[2] = number_maps[temp/10];
  192.         pattern[3] = number_maps[temp % 10];
  193.        
  194.     } else if ((opt_byte & FORMAT_MASK) == FORMAT_DEGREES) {
  195.         // Temperature display setup
  196.         show_apostrophe = true;
  197.         pattern[3] = PATTERN_c;
  198.         // only 1 dot position is valid
  199.         if ((opt_byte & DEGREES_DOT_POS_MASK) == 0b00100000) {
  200.             dot_postion = 1; // actual dot postions are numbered left to right
  201.         }      
  202.         // use all 4 bytes, but current display can only show 999 degs max
  203.         temp += data[1] * 16777216;
  204.         temp += data[2] * 65536;
  205.         temp += data[3] * 256;
  206.         temp += data[4];
  207.         temp %= 1000;
  208.         // convert the resulting integer to single digit patterns for display
  209.         pattern[0] = number_maps[temp/100];
  210.         temp %= 100;
  211.         pattern[1] = number_maps[temp/10];
  212.         temp %= 10;
  213.         pattern[2] = number_maps[temp];
  214.     } else if ((opt_byte & FORMAT_MASK) == FORMAT_DECIMAL) {
  215.         // A decimal digit
  216.         // Get the number of decimal places and convert it to the dot position
  217.         dot_postion = 3 - ((opt_byte & DECIMAL_DOT_POS_MASK) >> 4);
  218.         // Convert the 4 bytes to an integer, but current display can only show 9999 max
  219.         temp += data[1] * 16777216;
  220.         temp += data[2] * 65536;
  221.         temp += data[3] * 256;
  222.         temp += data[4];
  223.         temp %= 10000;
  224.         // convert the resulting integer to single digit patterns for display
  225.         pattern[0] = number_maps[temp/1000];
  226.         temp %= 1000;
  227.         pattern[1] = number_maps[temp/100];
  228.         temp %= 100;
  229.         pattern[2] = number_maps[temp/10];
  230.         temp %= 10;
  231.         pattern[3] = number_maps[temp];
  232.     }
  233.    
  234.     // Time to display what we've got
  235.     // set the colon and apostrophe as required
  236.     if (show_colon == true) { PORTA |= COLON_PIN; } else {  PORTA &= ~COLON_PIN; }
  237.     if (show_apostrophe == true) { PORTA |= DEG_PIN; } else { PORTA &= ~DEG_PIN; }
  238.  
  239.     // // Now show the pattern.
  240.     for (int d=0 ; d<NUM_DIGITS ; d++) {
  241.         // Choose the digit to display by setting it's pin HIGH and
  242.         // all the other pins LOW.
  243.         PORTD &= ~( d1 | d2 | d3 | d4);
  244.         PORTD |= digits[d];
  245.         // Actual dots are numbered left to right (0-3)
  246.         if (dot_postion != 3 && d == dot_postion) {
  247.             pattern[d] |= 0b00000001;  // turn on the dot for this segment
  248.         }
  249.         showPattern(pattern[d]);//
  250.     }
  251.  
  252. }
  253. //----------------------------------------------------------------------------
  254. void showPattern(uint8_t pattern) {
  255.     // show the current pattern on the currently selected digit
  256.  
  257.     // First set all the digit pins HIGH to turn them off so the
  258.     // previous digit doesn't get ghosted onto the new segment
  259.     // Segments a & b are on PORTD, the rest are on PORTB
  260.     PORTD |= (portd_segment_mask);
  261.     PORTB |= (portb_segment_mask);
  262.  
  263.     // Have to manipulate the pins one at a time so as not to interfere with I2C
  264.     // PORTD segments
  265.     if ((pattern & 128) == 128) { PORTD &= ~seg_a; } else { PORTD |= seg_a; }
  266.     if ((pattern & 64) == 64)   { PORTD &= ~seg_b; } else { PORTD |= seg_b; }
  267.     // PORTB segments
  268.     if ((pattern & 32) == 32)   { PORTB &= ~seg_c; } else { PORTB |= seg_c; }
  269.     if ((pattern & 16) == 16)   { PORTB &= ~seg_d; } else { PORTB |= seg_d; }
  270.     if ((pattern &  8) ==  8)   { PORTB &= ~seg_e; } else { PORTB |= seg_e; }
  271.     if ((pattern &  4) ==  4)   { PORTB &= ~seg_f; } else { PORTB |= seg_f; }
  272.     if ((pattern &  2) ==  2)   { PORTB &= ~seg_g; } else { PORTB |= seg_g; }
  273.     if ((pattern &  1) ==  1)   { PORTB &= ~seg_dp; } else { PORTB |= seg_dp; }
  274.     // Delay so the image stays on the retina
  275.     _delay_ms(POV_DELAY);
  276. }
  277. //----------------------------------------------------------------------------
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement