Introduction: DaveWare Led Board
The goal of this project is to build a custom size RGB Led screen based on 32x32 RGB Led panels. This project screen size/resolution is 96x64 (ie, using six -6- 32x32 RGB Led panels). This screen will be used for show information about weightlifting athletes attempts from a C# .NET application which manipulates an Excel file with these athletes information. This application was be programmed using Free Sharpdevelop IDE and .NET Framework 3.5
Step 1: Parts Needed
The parts needed are available from any supplier, but I prefer Sparkfun electronic supplier. The list is as follow:
- Six (6 units:3 columns,2 rows for 96x64 resolution) RGB LED Panel - 32x32
- One Teensy 3.1/3.2 (the computer)
- One WiFi Module ESP8266
- One Power Supply (30A). You can recycle any PC Power Supply. I used one from an old IBM Netvista Desktop
- Screen Frame made of aluminium profiles. This can be obtained locally easily.
- One PCB/stripboard with LED BOARD design
- Other electronics parts detailed in the circuit design: 1117 3.3v regulator, .
Step 2: How to Connect 32x32 RGB Led Panels
This step is the most important. We need to test our six (06) panels with our 5VDC power supply; also test if them works fine together.
For get this first goal, this link was very usable RGB Panel Hookup Guide from Sparkfun
Each RGB LED panel comes with two data cables, and one power cable. One of the data cables will be the INPUT from the computer (teensy 3.1/3.2) as show in figure above. The other data cable will be connected to the NEXT RGB LED panel and go on until reach the sixth panel.
Step 3: Programming the Computer (teensy 3.1/3.2)
The teensy 3.1/3.2 is an arduino compatible development board which I had selected because it has a great amount of RAM (64 Kb) that is used for the screen buffer. Continuously, the this screen buffer content will be shown in the 96x64 resolution LED screen. So, we need a timer routine/function that accomplishes this task.
We need a function to receive commands by WiFi network through the ESP8266 Module. This will read the data sent by the PC (and also android in a near future)
But first, we need to set the Arduino IDE 1.6.5 programming environment for support our computer (teensy 3.1/3.2) and also the ESP8266 - 01 WiFi Module. For this, we must follow this steps:
- Download and install the Arduino IDE 1.6.5 or greater
- Download and install the Teensyduino file (I did this in Windows 7) . This installer adds the necessary support files to Arduino IDE for teensy 3.1/3.2 board/computer.
- Done, we are ready for programming the teensy for control the RGB LED panels arrangement with our windows application by WiFi.
Secondly, in the teensy computer sketch, we need to define the configuration of pins for ESP8266 (UART) and the first 32x32 RGB LED panel.
/*<br>* * Modified by David Elías Flores Escalante, for manage an arrangement of six 32x32 RGB Led panels for * a 96x64 screen resolution. */
#include "glcdfont.h" const uint8_t NPANELS =6; const uint8_t NTRAMA =128; const uint8_t SIZEX = 32*NPANELS; const uint8_t SIZEY = 32;
#include "logo.h"
#define swap(a, b) { int16_t t = a; a = b; b = t; }
//PortC[0:11] = {15, 22, 23, 9, 10, 13, 11, 12, 28, 27, 29, 30} //PortD[0:7] = {2, 14, 7, 8, 6, 20, 21, 5} //Define pins const uint8_t //PortC APIN = 15, BPIN = 22, CPIN = 23, DPIN = 9, CLOCKPIN = 10, LATCHPIN = 13, OEPIN = 11, //PortD R1PIN = 2, R2PIN = 8, G1PIN = 14, G2PIN = 6, B1PIN = 7, B2PIN = 20;
uint8_t pinTable[13] = { R1PIN,R2PIN,G1PIN,G2PIN,B1PIN,B2PIN, APIN,BPIN,CPIN,DPIN,CLOCKPIN,LATCHPIN,OEPIN};
//Addresses 1/8 rows Through a decoder uint16_t const A = 1, B = 2,C = 4, D=8; //Acts like a 16 bit shift register uint16_t const SCLK = 16; uint16_t const LATCH = 32; uint16_t const OE = 64;
uint16_t const abcVar[16] = { //Decoder counter var 0,A,B,A+B,C,C+A,C+B,A+B+C, 0+D,A+D,B+D,A+B+D,C+D,C+A+D,C+B+D,A+B+C+D};
//Data Lines for row 1 red and row 9 red, ect. uint16_t const RED1 = 1, RED2 = 8; uint16_t const GREEN1 = 2, GREEN2 = 16; uint16_t const BLUE1 = 4, BLUE2 = 32;
static uint8_t gr, gg, gb; static int peso=25, intento=1,/* minutos=1,segundos=0,*/modalidad=1; static int oldMinD=60,oldMinU=600,oldSegD=60,oldSegU=60,oldColor=9393,tipo=0;
//Here is where the data is all read static byte ScreenBuffer[SIZEX*SIZEY*4];
int BufferIn[512];
//BAM and interrupt variables uint8_t rowN = 0; uint16_t BAM; uint8_t BAMMAX = 7; //now 24bit color! (0-7)
int cmd=0;
byte prevVal1, prevVal2,val; int datafromPC; boolean dataIn=false; int dataPos=0;
The sketch set the ESP8266 WiFi module as AP (Access Point), so, we don't need additional network hardware to connect our laptop (or PC with wireless capability) to the LED BOARD. For this, we need to send to ESP8266 AT Commands by serial interface by teensy UART pins:
/***************************************************************************<br> set ESP8266 ***************************************************************************/ void setup_ESP8266() { //Reset ESP8266 Serial1.println("AT+RST"); WaitOK(); //Set ESP8266 into CWMODE=1: AP Mode Serial1.println("AT+CWMODE=1"); WaitOK();
//Set ESP8266 into CIPMODE=1: Serial1.println("AT+CIPMODE=1"); WaitOK(); //Ask ESP8266 IP Number (AP and Station) Serial1.println("AT+CIFSR"); WaitOK(); //Set AP parameters. SSID, password Serial1.println("AT+CWSAP=\"LED_BOARD\",\"321654\",5,0"); WaitOK(); //Reset ESP8266 Serial1.println("AT+RST"); WaitOK(); //set ESP8266 for multiple connections Serial1.println("AT+CIPMUX=1"); WaitOK(); //Set ESP8266 Server Mode,Port Serial1.println("AT+CIPSERVER=1,9999"); WaitOK(); //Set ESP8266 Server timeout to 7200 seconds Serial1.println("AT+CIPSTO=28800"); WaitOK(); }
Now, we need to read data FROM the ESP8266 sent by the laptop/PC by WiFi.
if (Serial1.available())<br> { prevVal1 = prevVal2; prevVal2 = val; datafromPC= val = Serial1.read(); if (prevVal1==192 && prevVal2==192) // Peso //else if(prevVal1=='p' && prevVal2=='e'&& val=='s') { dataPos=0; dataIn=true; cmd=1; if(Serial) Serial.println("command 1"); } if (prevVal1==108 && prevVal2==108) // Intento //else if(prevVal1=='i' && prevVal2=='n'&& val=='t') { dataPos=0; dataIn=true; cmd=2; if(Serial) Serial.println("command 2"); } if (prevVal1==109 && prevVal2==109) // Modalidad //else if(prevVal1=='m' && prevVal2=='o'&& val=='d') { dataPos=0; dataIn=true; cmd=3; if(Serial) Serial.println("command 3"); } if (prevVal1==110 && prevVal2==110) // Cronometro //else if(prevVal1=='m' && prevVal2=='o'&& val=='d') { dataPos=0; dataIn=true; cmd=4; if(Serial) Serial.println("command 4"); } if (prevVal1==111 && prevVal2==111) // Atleta //else if(prevVal1=='m' && prevVal2=='o'&& val=='d') { dataPos=0; dataIn=true; cmd=5; if(Serial) Serial.println("command 5"); } if (prevVal1==112 && prevVal2==112) // Nombre Liga //else if(prevVal1=='m' && prevVal2=='o'&& val=='d') { dataPos=0; dataIn=true; cmd=6; if(Serial) Serial.println("command 6"); } if (prevVal1==140 && prevVal2==140) // Receso { dataPos=0; dataIn=true; cmd=8; if(Serial) Serial.println("command 8"); } if (prevVal1==160 && prevVal2==160) // tipo pantalla { dataPos=0; dataIn=true; cmd=9; if(Serial) Serial.println("command 9"); } if (prevVal1==170 && prevVal2==170) // nuevo { dataPos=0; dataIn=true; cmd=20; if(Serial) Serial.println("command 20"); } if (prevVal1==113 && prevVal2==113) // Fecha y Hora //else if(prevVal1=='m' && prevVal2=='o'&& val=='d') { dataPos=0; dataIn=true; cmd=7; if(Serial) Serial.println("command 7"); } if(prevVal1==150 && prevVal2==150 && val==150) // FIN DE TRAMA //if(prevVal1=='f' && prevVal2=='i' && val=='n') { dataIn=false; if(cmd==1) //PESO { PrintScreen_Peso(&BufferIn[0]); } if(cmd==2) //INTENTO { PrintScreen_Intento(&BufferIn[0]); } if(cmd==3) //MODALIDAD { modalidad=BufferIn[0]; PrintScreen_Modalidad(modalidad); } if(cmd==4) //CRONOMETRO { PrintScreen_Timer(&BufferIn[0]); /*if(minD==0&&minU==0&&segD==0&&segU==0) oldMinD=oldMinU=oldSegD=60;*/ } if(cmd==5) //ATLETA { PrintScreen_Atleta(&BufferIn[0]); } if(cmd==8) //RECESO { PrintScreen_Receso(&BufferIn[0]); } if(cmd==9) //tipo Pantalla { tipo=BufferIn[0]; clrScreen(); switch(tipo) { case 0: PrintScreen_Logo(); break; case 1: PrintScreen_Titulo_Levantamiento(); break; case 2: PrintScreen_Titulo_Receso(); break; case 3: TestScreen_01(); break; }; //PrintScreen_Tipo(&BufferIn[0]); } if(cmd==7) //Fecha y Hora { PrintScreen_FechaHora(&BufferIn[0]); } cmd=0; val=' '; } if(prevVal1=='s' && prevVal2=='c'&& val=='c') { for(int i=0;i<4096*NPANELS;i++) { if(Serial) { Serial.print(ScreenBuffer[i]); Serial.print(","); if(i%96==0) Serial.print("\n\r"); } } val=' '; } if(prevVal1=='c' && prevVal2=='l' && val=='s') { clrScreen(); if(Serial) { Serial.println("Pantalla Borrada"); } val=' '; } if(prevVal1=='f' && prevVal2=='i'&& val=='l') { fillScreen(0xff, 0xff, 0x00); if(Serial) { Serial.println("Prueba Pantalla"); } val=' '; } if(prevVal1=='r' && prevVal2=='s'&& val=='t') { oldMinD=oldMinU=oldSegD=oldSegU=60; if(Serial) { Serial.println("Pantalla Reiniciada"); } val=' '; } if(prevVal1=='l' && prevVal2=='o'&& val=='g') { for(int i=0;i<sizex*sizey*4;i++) ="" screenbuffer[i]="logo[i];" ="" ="" ="" if(serial)="" {="" serial.println("pantalla="" muestra="" logo="" daveware");="" } ="" val=" " ;="" ="" }="" ="" if(prevval1="='s'" &&="" prevval2="='c'&&" { ="" string="" msgstring="DaveWare" msgstring.reserve(200);="" scrooltext(0,0,msgstring="" ,="" 0x0000ff,="" 1,50);="" { ="" ; ="" 1,25);="" <="" p=""></sizex*sizey*4;i++)>
if(prevVal1=='t' && prevVal2=='s'&& val=='x') { TestScreen_01(); } else if(dataIn) { BufferIn[dataPos++]=datafromPC; } } }
Finally, the timer routine for draw the screen buffer content to the LED BOARD:
IntervalTimer timer1;<br> void timerInit() { BAM = 0; attackMatrix(); }
//The updating matrix stuff happens here //each pair of rows is taken through its BAM cycle //then the rowNumber is increased and id done again void attackMatrix() { timer1.end(); uint16_t portData; portData = 0; // Clear data to enter portData |= (abcVar[rowN])|OE; // abc, OE portData &=~ LATCH; // LATCH LOW GPIOC_PDOR = portData; // Write to Port uint8_t *start = &ScreenBuffer[rowN*SIZEX*8+((7-BAMMAX)+BAM)*32*NPANELS]; for(uint8_t i = 0; i < 32*NPANELS; i++) { GPIOD_PDOR = start[i]; // Transfer data GPIOC_PDOR |= SCLK;// Clock HIGH GPIOC_PDOR &=~ SCLK;// Clock LOW }
GPIOC_PDOR |= LATCH;// Latch HIGH GPIOC_PDOR &=~ OE;// OE LOW, Displays line
#define LOOPTIME 1 //trial&error to get both smooth gradients & little flicker #define CALLOVERHEAD 0 timer1.begin(attackMatrix,((LOOPTIME+CALLOVERHEAD)<<bam)-calloverhead); ="" ="" if(bam="">= BAMMAX) //Checks the BAM cycle for next time. { if(rowN == 15) { rowN = 0; } else { rowN ++; } BAM = 0; } else { BAM ++; } }</bam)-calloverhead);>
Step 4: C# .NET Windows Application
This step explains how to the C# .NET Windows Application controls the LED BOARD by commands serially sent by WiFi link established by ESP8266 Module.
- Open the application
- Select option menu
- We need to configure the WiFi connection with the LED BOARD. The ESP8266 when works as an Access Point uses the IP address 192.168.4.1. The PORT in the teensy sketch is 9999.
- Select option/button Conectar for connect Laptop/PC with the LED BOARD.
- Now, we need the list of athletes who are going to participate in competition. You can enter them using the excel template file named campeonato.xls; filling in Excel ALL the records except those referring attempts results.
- Open from the application, the competition file (included within the folder) in excel named campeonato.xls
- Now, you can select any athlete in list in the listview above, and you will see his data into the LED BOARD just using a click.
- For use the application, just click iniciar/pausar button (start/pause, for start or pause the countdown timer); and reiniciar button (restart, for reset count, or finish a PAUSED attempt)
- Finally, according the judges decision, set the lifting attempt valid or avoid. This result will be record in the listview bellow; and save the results into an Excel file with the name you prefer.
Attachments
Step 5: Sketchup Model
Finally, the sketchup model using the aluminium frame measures. This is not necessary for test LED BOARD, but is great to see the screen finished with its aluminium frame.
I included my sketchup unfinished model. Back cover and power supply mount is not finished yet.