SHOW:
|
|
- or go back to the newest paste.
1 | /* | |
2 | - | * FourDigitSevenSegmentDisplayDriver.c |
2 | + | Testing I2C comms to my ATtiny2313 |
3 | - | * |
3 | + | |
4 | - | * Created: 1/31/2012 1:09:17 AM |
4 | + | |
5 | - | * Author: grist.carrigafoyl |
5 | + | #include <Wire.h> |
6 | - | |
6 | + | |
7 | - | Code to turn an ATtiny2313 into a 4 digit 7 segment display driver. This will |
7 | + | // local LED pins |
8 | - | allow offloading multiplexing a typical LED display to a slave chip and |
8 | + | #define LED1 8 |
9 | - | let the main CPU get on with whatever it's doing. The driver displays |
9 | + | #define LED2 9 |
10 | - | whatever is in its data register until it receives new data over the |
10 | + | #define LED3 10 |
11 | - | serial lines. |
11 | + | #define LED4 11 |
12 | ||
13 | - | Employs a 5 byte protocol with the first byte containing flags that control |
13 | + | // Array to hold the led pin numbers |
14 | - | the colon and degrees indication and also how the data is displayed |
14 | + | int LEDS[4] = {LED1, LED2, LED3, LED4}; |
15 | - | and the other 4 bytes contain the data to be displayed. |
15 | + | const int SLAVE_ADDRESS = 0x01;// this must match the address assigned to the ATtiny in its code or they won't talk |
16 | ||
17 | - | Using Don Blake's translation of the Atmel I2C (TWI) library. |
17 | + | // setup |
18 | void setup() { | |
19 | - | First byte |
19 | + | Wire.begin(); |
20 | - | First 4 bits are format related |
20 | + | for (byte i=0;i<4;i++) { |
21 | - | 1 (128) - bit 1 of format |
21 | + | pinMode(LEDS[i], OUTPUT); |
22 | - | 2 (64) - bit 2 of format |
22 | + | } |
23 | - | 3 (32) - bit 1 of format params |
23 | + | |
24 | - | 4 (16) - bit 2 of format params |
24 | + | |
25 | - | Second 4 bits are display option related (not implemented for now) |
25 | + | // Main |
26 | - | 5 (8) - flashing (not implemented) |
26 | + | void loop () { |
27 | - | 6 (4) - scrolling (not implemented) |
27 | + | |
28 | - | 7 (2) - bit 1 of display option params |
28 | + | // Demonstrate each of the display modes available |
29 | - | 8 (1) - bit 2 of display option params |
29 | + | delay(1000); |
30 | testRaw(); | |
31 | delay(1000); | |
32 | testTime(); | |
33 | - | #define F_CPU 8000000UL // 8Mhz |
33 | + | delay(1000); |
34 | testDegrees(); | |
35 | - | #define NUM_DIGITS 4 |
35 | + | delay(1000); |
36 | - | #define NUM_SEGMENTS 8 // a 7 segment display has 8 segments. #8 is the decimal point |
36 | + | testDecimal(); |
37 | - | #define NUM_BYTES_IN_PROTOCOL 5 // how many bytes to read at a time |
37 | + | delay(1000); |
38 | ||
39 | - | #include <avr/io.h> |
39 | + | |
40 | - | #include <util/delay.h> |
40 | + | |
41 | - | #include <avr/interrupt.h> // for I2C |
41 | + | //------------------------------------------------------------------- |
42 | // Functions | |
43 | - | #include "usiTwiSlave.h" // Don Blake's library |
43 | + | //------------------------------------------------------------------- |
44 | void testRaw() { | |
45 | - | // The TWI address for this slave device |
45 | + | // test the raw mode |
46 | - | const uint8_t TWI_SLAVE_ADDRESS = 0x01; |
46 | + | |
47 | // A simple set of patterns to display. | |
48 | - | // Constants for option byte bitmapping. First 4 bits are for the display format |
48 | + | byte number_maps[15] = { |
49 | - | const uint8_t FORMAT_MASK = 0b11000000; |
49 | + | //abcdefgp - 1 for on, 0 for off. |
50 | - | const uint8_t FORMAT_OPTION_MASK = 0b00110000; |
50 | + | B11000111, |
51 | - | // RAW format masks |
51 | + | B00111010, |
52 | - | const uint8_t FORMAT_RAW = 0b00000000; // Param bits are colon & apostrophe |
52 | + | B11000110, |
53 | - | const uint8_t RAW_OPTION_COLON = 0b00100000; |
53 | + | B00111010, |
54 | - | const uint8_t RAW_OPTION_APOSTROPHE = 0b00010000; |
54 | + | B11000110, |
55 | - | // TIME format masks |
55 | + | B00111010, |
56 | - | const uint8_t FORMAT_TIME = 0b10000000; // (could have param for 24 hr? indicated by dot in pos 1) |
56 | + | B11000110, |
57 | - | const uint8_t TIME_OPTION_HHMM = 0b00100000; |
57 | + | B00111010, |
58 | - | const uint8_t TIME_OPTION_MMSS = 0b00010000; |
58 | + | B11000110, |
59 | - | const uint8_t TIME_OPTION_SECONDS = 0b00110000; |
59 | + | B00111010, |
60 | - | // DEGREES format masks |
60 | + | }; |
61 | - | const uint8_t FORMAT_DEGREES = 0b11000000; // Param bits are point position indicator, 0 or 1 are off, only positions 2 & 3 are valid) |
61 | + | |
62 | - | const uint8_t DEGREES_DOT_POS_MASK = 0b00110000; |
62 | + | byte option_byte = B00110000; // turn the colon & apostrophe on |
63 | - | // DECIMAL format masks |
63 | + | for (int i=0;i<3;i++){ |
64 | - | const uint8_t FORMAT_DECIMAL = 0b01000000; // Param bits are point postion indicator 0 is off, 123 count from right) |
64 | + | for (byte i = 0; i<10; i++) { |
65 | - | const uint8_t DECIMAL_DOT_POS_MASK = 0b00110000; |
65 | + | displayData(i); // show the current data on the locallly connected LEDs |
66 | ||
67 | - | // Now the display options in the last 4 bits. Not implemented as yet. |
67 | + | Wire.beginTransmission(SLAVE_ADDRESS); |
68 | - | const uint8_t OPTION_FLASHING = 0b00001000; // delay as 2 bit param. Not implemented yet |
68 | + | Wire.write(option_byte); |
69 | - | const uint8_t OPTION_SCROLLING = 0b00000100; // 2 bit param for direction. Not implemented yet |
69 | + | for (int x=0;x<4;x++) { |
70 | - | const uint8_t OPTION_PARAM0 = 0b00000000; |
70 | + | Wire.write(number_maps[((i+x) % 10)]); |
71 | - | const uint8_t OPTION_PARAM1 = 0b00010000; |
71 | + | } |
72 | - | const uint8_t OPTION_PARAM2 = 0b00100000; |
72 | + | Wire.endTransmission(); |
73 | - | const uint8_t OPTION_PARAM3 = 0b00110000; |
73 | + | delay(100); |
74 | } | |
75 | - | // Number bitmaps. Which LEDs to light up to represent each digit |
75 | + | //delay(250); |
76 | - | const uint8_t number_maps[10] = { |
76 | + | } |
77 | - | //abcdefgp - 1 for on, 0 for off. |
77 | + | |
78 | - | 0b11111100, // 0 |
78 | + | //------------------------------------------------------------------- |
79 | - | 0b01100000, // 1 |
79 | + | void testTime() { |
80 | - | 0b11011010, // 2 |
80 | + | // test the time mode |
81 | - | 0b11110010, // 3 |
81 | + | // slave is only reading mm:ss for now |
82 | - | 0b01100110, // 4 |
82 | + | char option_byte = B10000000; |
83 | - | 0b10110110, // 5 |
83 | + | for (byte m=5;m<15;m++) { |
84 | - | 0b10111110, // 6 |
84 | + | for (byte s=0;s<60;s++) { |
85 | - | 0b11100000, // 7 |
85 | + | Wire.beginTransmission(SLAVE_ADDRESS); |
86 | - | 0b11111110, // 8 |
86 | + | Wire.write(option_byte); |
87 | - | 0b11110110, // 9 |
87 | + | Wire.write((char)B00000001); // hours ignored for now |
88 | - | }; |
88 | + | Wire.write((char)m); |
89 | - | const uint8_t PATTERN_c = 0b00011010; // lower case 'c' for degrees display |
89 | + | Wire.write((char)s); |
90 | Wire.write((char)B00000100); // 10th seconds ignored for now | |
91 | Wire.endTransmission(); | |
92 | - | // Segment to pin mapping. |
92 | + | delay(20); |
93 | - | enum SEGMENT_PINS { |
93 | + | |
94 | - | seg_a = _BV(PD0), |
94 | + | } |
95 | - | seg_b = _BV(PD1), |
95 | + | |
96 | - | seg_c = _BV(PB6), |
96 | + | //------------------------------------------------------------------- |
97 | - | seg_d = _BV(PB4), |
97 | + | void testDegrees() { |
98 | - | seg_e = _BV(PB3), |
98 | + | // test the degrees mode |
99 | - | seg_f = _BV(PB2), |
99 | + | |
100 | - | seg_g = _BV(PB1), |
100 | + | byte option_byte= B11100000; |
101 | - | seg_dp = _BV(PB0) |
101 | + | // just whole numbers for now. hacking 4 bytes together. If your temp |
102 | - | }; |
102 | + | // will never exceed 255 you can just send 3 zeros and the raw temp. |
103 | - | // Digit to pin mapping. |
103 | + | for (int x=0; x<2 ; x++ ) { |
104 | - | enum DIGIT_PINS { |
104 | + | for (int y=200; y<256 ; y++ ) { // cut down range for testing |
105 | - | d1 = _BV(PD3), |
105 | + | Wire.beginTransmission(SLAVE_ADDRESS); |
106 | - | d2 = _BV(PD4), |
106 | + | Wire.write(option_byte); |
107 | - | d3 = _BV(PD5), |
107 | + | Wire.write((byte)0); |
108 | - | d4 = _BV(PD6) |
108 | + | Wire.write((byte)0); |
109 | - | }; |
109 | + | Wire.write((byte)x); |
110 | Wire.write((byte)y); | |
111 | - | // The colon and degree indicator LEDs |
111 | + | Wire.endTransmission(); |
112 | - | const uint8_t COLON_PIN = _BV(PA0); |
112 | + | delay(100); |
113 | - | const uint8_t DEG_PIN = _BV(PA1); // degrees indicator (apostrophe) |
113 | + | |
114 | } | |
115 | - | // Having a delay between displaying segments helps the persistence of vision and makes the segments brighter. |
115 | + | |
116 | - | // Much larger than this you will see noticeable flickering, much lower and you get dimmed segments. |
116 | + | |
117 | - | const int POV_DELAY = 5; // ms delay for persistence of vision |
117 | + | |
118 | //------------------------------------------------------------------- | |
119 | - | // Digit and segment pins |
119 | + | void testDecimal() { |
120 | - | uint8_t digits[4] = {d1,d2,d3,d4}; |
120 | + | // test the decimal mode |
121 | - | // Segment pins are split over 2 ports as I2C needs 2 pins on PORTB |
121 | + | int temp; |
122 | - | uint8_t portb_segment_mask = (seg_c | seg_d | seg_e | seg_f | seg_g | seg_dp); |
122 | + | for (int i=500;i<2000;i++) { |
123 | - | uint8_t portd_segment_mask = (seg_a | seg_b); |
123 | + | temp = i; |
124 | - | volatile uint8_t data[NUM_BYTES_IN_PROTOCOL] = {0,255,255,255,255}; // this will hold the data to be displayed |
124 | + | Wire.beginTransmission(SLAVE_ADDRESS); |
125 | Wire.write((byte)B01110000); //option byte | |
126 | - | // Function prototypes |
126 | + | // the number is broken into 4 bytes. Most significant byte first. |
127 | - | void displayData(); |
127 | + | // Quick and dirty hack with constants. |
128 | - | void showPattern(uint8_t pattern); |
128 | + | Wire.write((byte)(temp/16777216)); |
129 | temp %= 16777216; | |
130 | - | int main(void) |
130 | + | Wire.write((byte)(temp/65536)); |
131 | - | { |
131 | + | temp %= 65536; |
132 | - | // Set the pin modes for output |
132 | + | Wire.write((byte)(temp/256)); |
133 | - | DDRA |= (COLON_PIN | DEG_PIN); |
133 | + | temp %= 256; |
134 | - | DDRB |= portb_segment_mask; // all pins except SDA & SCL (PB5 & 7) on PortB are output |
134 | + | Wire.write((byte)temp); |
135 | - | DDRD |= (d1 | d2 | d3 | d4 | portd_segment_mask ); // the digit selector pins & 2 of the segment pins |
135 | + | Wire.endTransmission(); |
136 | - | |
136 | + | delay(20); |
137 | - | // Initialise the I2C interface |
137 | + | } |
138 | - | usiTwiSlaveInit(TWI_SLAVE_ADDRESS); |
138 | + | |
139 | - | // Enable global interrupts (required for I2C) |
139 | + | //------------------------------------------------------------------- |
140 | - | sei(); |
140 | + | void displayData(byte pattern) { |
141 | // show the current data on this device's leds. | |
142 | - | // main loop |
142 | + | // first blank out the leds |
143 | - | for(;;) { // forever |
143 | + | for (byte i=0;i<4;i++) { |
144 | - | // Check to see if there's data to read in |
144 | + | digitalWrite(LEDS[i], LOW); |
145 | - | if (usiTwiDataInReceiveBuffer()) { |
145 | + | } |
146 | - | // get some bytes |
146 | + | byte pat = pattern; |
147 | - | for (int i=0;i<NUM_BYTES_IN_PROTOCOL;i++) { |
147 | + | byte i = 0; |
148 | - | data[i] = usiTwiReceiveByte(); |
148 | + | while (pat > 0 && i < 4) { |
149 | - | } |
149 | + | if ((pat % 2) == 1) { |
150 | - | } |
150 | + | digitalWrite(LEDS[i], HIGH); |
151 | - | // show the current data |
151 | + | } |
152 | - | displayData(); |
152 | + | pat = pat / 2; |
153 | i++; | |
154 | } | |
155 | } |