Thursday, April 25, 2013

My first Arduino project

At work we print identification characters on the circuits we fabricate using a microscope and a matrix of ultraviolet LEDs. To do the same thing for our scaled up Gen II panels we needed to build another ID printer. This printer would shine ultraviolet light through an optics train to expose a patch of photoresist on the device during production.

We decided to control the 9x5 LED matrix using 14 digital outputs on the Arduino Micro because it simplified the hardware design.

/*
  RS232_MATRIX_CONTROL_v2p0
  Single character driver for LED matrix display. Current code is hardcoded to display 46 characters on a 9 row by 5 column matrix. 
  Each character is sent through serial terminal followed by a carriage return. 
  
  Jovan Trujillo
  Arizona State University
  03/27/2013
*/  
 
byte RN[] = {4,5,6,7,8,9,10,11,12};
byte CN[] = {23,22,21,20,19};
byte LED = 13;
byte strobe = 2;  // strobe rate for each row of matrix in milliseconds.
byte inByte = 0; // Input character received from serial port.
byte idx = 0;  // Generic index counter.
byte i = 0;    // Generic index counter.
int exposure = 250;  // Number of times entire character is displayed.
// Exposure time is calculated to be: strobe x # rows x exposure
byte rowcnt = 9;     // Number of rows to display for matrix arrays that have fewer than 9 rows.
// Character database contains the column bit patterns for each row in an array.
// Character database is hardcoded for a 9x5 LED matrix. 
byte D_0[] = {17,14,14,12,10,6,14,14,17};         // 1
byte D_1[] = {3,27,27,27,27,26,26,26,0};          // 2
byte D_2[] = {17,14,30,30,30,17,15,15,16};        // 3
byte D_3[] = {1,30,30,30,17,30,30,30,1};          // 4
byte D_4[] = {15,15,14,14,14,0,30,30,30};         // 5
byte D_5[] = {16,23,23,23,16,30,30,14,17};        // 6
byte D_6[] = {23,15,15,15,15,0,14,14,0};          // 7
byte D_7[] = {0,14,30,30,29,27,27,27,27};         // 8
byte D_8[] = {17,21,21,21,0,14,14,14,0};          // 9
byte D_9[] = {0,14,14,0,30,30,30,30,29};          // 10
byte D_A[] = {27,21,14,14,14,0,14,14,14};         // 11
byte D_B[] = {1,14,14,14,1,14,14,14,1};           // 12
byte D_C[] = {24,23,15,15,15,15,15,23,24};        // 13
byte D_D[] = {3,21,22,22,22,22,22,21,3};          // 14
byte D_E[] = {0,15,15,15,3,15,15,15,0};           // 15
byte D_F[] = {0,15,15,3,15,15,15,15,15};          // 16
byte D_G[] = {24,23,15,15,15,12,14,14,17};        // 17
byte D_H[] = {14,14,14,14,0,14,14,14,14};         // 18
byte D_I[] = {0,27,27,27,27,27,27,27,0};          // 19
byte D_J[] = {30,30,30,30,30,30,14,14,17};        // 20
byte D_K[] = {14,13,11,7,15,7,11,13,14};          // 21
byte D_L[] = {15,15,15,15,15,15,15,15,0};         // 22
byte D_M[] = {14,4,10,10,10,14,14,14,14};         // 23
byte D_N[] = {14,6,6,10,10,10,12,12,14};          // 24
byte D_O[] = {27,21,14,14,14,14,14,21,27};        // 25
byte D_P[] = {1,14,14,14,1,15,15,15,15};          // 26
byte D_Q[] = {30,26,22,14,14,14,10,9,22};         // 27
byte D_R[] = {1,14,14,1,15,7,11,13,14};           // 28
byte D_S[] = {17,14,15,23,27,29,30,14,17};        // 29
byte D_T[] = {0,10,27,27,27,27,27,27,27};         // 30
byte D_U[] = {14,14,14,14,14,14,14,14,0};         // 31
byte D_V[] = {14,14,14,14,14,14,14,21,27};        // 32
byte D_W[] = {14,14,14,10,10,10,10,10,21};        // 33
byte D_X[] = {14,14,14,21,27,21,14,14,14};        // 34
byte D_Y[] = {14,14,14,21,27,27,27,27,27};        // 35
byte D_Z[] = {0,30,30,21,27,21,15,15,0};          // 36
byte COLON[] = {31,17,17,17,31,17,17,17,31};      // 37
byte SEMICOLON[] = {17,17,17,31,17,17,17,25,23};  // 38
byte LESSTHAN[] = {30,29,27,23,15,23,27,29,30};   // 39
byte EQUAL[] = {31,31,0,31,31,31,0,31,31};        // 40
byte GRTRTHAN[] = {15,23,27,29,30,29,27,23,15};   // 41
byte QUESTION[] = {17,14,30,25,27,27,31,27,31};   // 42
byte D_AT[] = {31,0,14,8,10,8,15,0,31};           // 43
byte D_DASH[] = {31,31,31,0,0,0,31,31,31};        // 44
byte D_SPC[] = {31,31,31,31,31,31,31,31,31};      // 45
byte D_PER[] = {31,31,31,31,31,31,17,17,17};      // 46
byte D_BLK[] = {0,0,0,0,0,0,0,0,0};               // 47

char datalist[47];  // datalist holds an array of all available chracters to pattern match.
byte *decodelist[47]; // decodelist holds an array of memory references to the bit patterns for each character.
byte *refval = 0;  // refval contains a reference to the bit pattern for a specific character entered through the serial terminal.

// the setup routine runs once when you press reset:
void setup() {  
  // Initialize datalist with valid characters.  
  datalist[0] = '0';
  datalist[1] = '1';
  datalist[2] = '2';
  datalist[3] = '3';
  datalist[4] = '4';
  datalist[5] = '5';
  datalist[6] = '6';
  datalist[7] = '7';
  datalist[8] = '8';
  datalist[9] = '9';
  datalist[10] = 'A';
  datalist[11] = 'B';
  datalist[12] = 'C';
  datalist[13] = 'D';
  datalist[14] = 'E';
  datalist[15] = 'F';
  datalist[16] = 'G';
  datalist[17] = 'H';
  datalist[18] = 'I';
  datalist[19] = 'J';
  datalist[20] = 'K';
  datalist[21] = 'L';
  datalist[22] = 'M';
  datalist[23] = 'N';
  datalist[24] = 'O';
  datalist[25] = 'P';
  datalist[26] = 'Q';
  datalist[27] = 'R';
  datalist[28] = 'S';
  datalist[29] = 'T';
  datalist[30] = 'U';
  datalist[31] = 'V';
  datalist[32] = 'W';
  datalist[33] = 'X';
  datalist[34] = 'Y';
  datalist[35] = 'Z';
  datalist[36] = ':';
  datalist[37] = ';';
  datalist[38] = '<';
  datalist[39] = '=';
  datalist[40] = '>';
  datalist[41] = '?';
  datalist[42] = '@';
  datalist[43] = '-';
  datalist[44] = ' ';
  datalist[45] = '.';
  datalist[46] = '*';
  
  // Initialize decodelist with references to the bit patterns for valid characters.
  decodelist[0] = D_0;
  decodelist[1] = D_1;
  decodelist[2] = D_2;
  decodelist[3] = D_3;
  decodelist[4] = D_4;
  decodelist[5] = D_5;
  decodelist[6] = D_6;
  decodelist[7] = D_7;
  decodelist[8] = D_8;
  decodelist[9] = D_9;
  decodelist[10] = D_A;
  decodelist[11] = D_B;
  decodelist[12] = D_C;
  decodelist[13] = D_D;
  decodelist[14] = D_E;
  decodelist[15] = D_F;
  decodelist[16] = D_G;
  decodelist[17] = D_H;
  decodelist[18] = D_I;
  decodelist[19] = D_J;
  decodelist[20] = D_K;
  decodelist[21] = D_L;
  decodelist[22] = D_M;
  decodelist[23] = D_N;
  decodelist[24] = D_O;
  decodelist[25] = D_P;
  decodelist[26] = D_Q;
  decodelist[27] = D_R;
  decodelist[28] = D_S;
  decodelist[29] = D_T;
  decodelist[30] = D_U;
  decodelist[31] = D_V;
  decodelist[32] = D_W;
  decodelist[33] = D_X;
  decodelist[34] = D_Y;
  decodelist[35] = D_Z;
  decodelist[36] = COLON;
  decodelist[37] = SEMICOLON;
  decodelist[38] = LESSTHAN;
  decodelist[39] = EQUAL;
  decodelist[40] = GRTRTHAN;
  decodelist[41] = QUESTION;
  decodelist[42] = D_AT;
  decodelist[43] = D_DASH;
  decodelist[44] = D_SPC;
  decodelist[45] = D_PER;
  decodelist[46] = D_BLK;
  
  // Initialize serial and wait for port to open:
  Serial.begin(9600);

  Serial.println("Started...\n");
   
  // initialize the digital pin as an output.
  pinMode(4, OUTPUT);
  pinMode(5, OUTPUT);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
  pinMode(8, OUTPUT);
  pinMode(9, OUTPUT);     
  pinMode(10, OUTPUT);
  pinMode(11, OUTPUT);
  pinMode(12, OUTPUT);
  pinMode(19, OUTPUT);
  pinMode(20, OUTPUT);
  pinMode(21, OUTPUT);
  pinMode(22, OUTPUT);
  pinMode(23, OUTPUT);
  
  // Initialize LED matrix to OFF state. This will have to change for different array dimensions.
  for (i=0; i<=8; i++) {
    digitalWrite(RN[i], HIGH);
  }
  for (i=0; i<=4; i++) {
    digitalWrite(CN[i], LOW);
  }

}

// the loop routine runs over and over again forever:
void loop() {
  // read from port 3
  // TODO: Need to shut off serial port if using pins 0 and 1 for digital I/O

  while (Serial.available() > 0) {
    inByte = Serial.read();
  
  // Find serial input character in datalist and set refval to bit pattern reference based on datalist index.
  if (Serial.read() == '\r') {
  idx = exposure;
  for (i=0; i<=46; i++) {
    if (datalist[i] == inByte) {
       idx = i;
    }
  }
  refval = decodelist[idx];
  if (idx != exposure) {
    idx = 0;
  }
  
// Write bit pattern to LED matrix. 

  while (idx < exposure) {
    for (i=0; i<rowcnt; i++) {
        digitalWrite(RN[i], LOW);
        digitalWrite(CN[4], !bitRead(refval[i],4));
        digitalWrite(CN[3], !bitRead(refval[i],3));
        digitalWrite(CN[2], !bitRead(refval[i],2));
        digitalWrite(CN[1], !bitRead(refval[i],1));
        digitalWrite(CN[0], !bitRead(refval[i],0));
        delay(strobe);
        digitalWrite(RN[i],HIGH);
      }
    digitalWrite(RN[i], HIGH);
    digitalWrite(CN[0], LOW);
    digitalWrite(CN[1], LOW);
    digitalWrite(CN[2], LOW);
    digitalWrite(CN[3], LOW);
    digitalWrite(CN[4], LOW);    
  idx = idx + 1;
  }
  Serial.println(inByte, DEC);
  }
  }
}