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 | } |