422 lines
14 KiB
Plaintext
422 lines
14 KiB
Plaintext
#define BAUD 115200
|
|
|
|
//TLC5940NT pin definitions
|
|
#define VPRG 2
|
|
#define SIN 11
|
|
#define SCLK 13
|
|
#define XLAT 4
|
|
#define BLANK 5
|
|
#define DCPRG 6
|
|
#define GSCLK 7
|
|
|
|
#define MISO 12 //No se usan
|
|
#define SS 10 //No se usan
|
|
|
|
#include <EEPROM.h>
|
|
|
|
// start reading from the first byte (address 0) of the EEPROM
|
|
int address = 0;
|
|
|
|
byte intensidad=250; //0 - 4095
|
|
|
|
const byte remap[7][5] = { //Mapeo de los leds
|
|
{6,17,24,35,42},
|
|
{5,16,23,34,41},
|
|
{4,11,22,33,40},
|
|
{3,10,21,32,39},
|
|
{2,9,20,27,38},
|
|
{1,8,19,26,37},
|
|
{0,7,18,25,36},
|
|
};
|
|
|
|
int modo= 0;
|
|
|
|
byte numero[10][7] = { { B01110, B10001, B10011, B10101, B11001, B10001, B01110}, //48 = '0'
|
|
{ B00100, B01100, B10100, B00100, B00100, B00100, B11111}, //49 = '1'
|
|
{ B01110, B10001, B00001, B00110, B01000, B10000, B11111}, //50 = '2'
|
|
{ B01110, B10001, B00001, B01110, B00001, B10001, B01110}, //51 = '3'
|
|
{ B00010, B00110, B01010, B10010, B11111, B00010, B00010}, //52 = '4'
|
|
{ B11111, B10000, B11110, B00001, B00001, B10001, B01110}, //53 = '5'
|
|
{ B01110, B10001, B10000, B11110, B10001, B10001, B01110}, //54 = '6'
|
|
{ B11111, B00001, B00010, B00100, B01000, B10000, B10000}, //55 = '7'
|
|
{ B01110, B10001, B10001, B01110, B10001, B10001, B01110}, //56 = '8'
|
|
{ B01110, B10001, B10001, B01111, B00001, B10001, B01110}, //57 = '9'
|
|
};
|
|
|
|
byte caracterA[13][7] = {{ B01110, B10001, B10001, B11111, B10001, B10001, B10001}, //65 = 'A'
|
|
{ B11110, B10001, B10001, B11110, B10001, B10001, B11110}, //66 = 'B'
|
|
{ B01110, B10001, B10000, B10000, B10000, B10001, B01110}, //67 = 'C'
|
|
{ B11110, B10001, B10001, B10001, B10001, B10001, B11110}, //68 = 'D'
|
|
{ B11111, B10000, B10000, B11110, B10000, B10000, B11111}, //69 = 'E'
|
|
{ B11111, B10000, B10000, B11110, B10000, B10000, B10000}, //70 = 'F'
|
|
{ B01110, B10001, B10000, B10111, B10001, B10001, B01110}, //71 = 'G'
|
|
{ B10001, B10001, B10001, B11111, B10001, B10001, B10001}, //72 = 'H'
|
|
{ B11111, B00100, B00100, B00100, B00100, B00100, B11111}, //73 = 'I'
|
|
{ B00001, B00001, B00001, B00001, B10001, B10001, B01110}, //74 = 'J'
|
|
{ B10001, B10010, B10100, B11000, B10100, B10010, B10001}, //75 = 'K'
|
|
{ B10000, B10000, B10000, B10000, B10000, B10000, B11111}, //76 = 'L'
|
|
{ B10001, B11011, B10101, B10001, B10001, B10001, B10001}, //77 = 'M'
|
|
};
|
|
|
|
byte caracterB[14][7] = {{ B10001, B11001, B10101, B10011, B10001, B10001, B10001}, //78 = 'N'
|
|
{ B01110, B10001, B10001, B10001, B10001, B10001, B01110}, //79 = 'O'
|
|
{ B11110, B10001, B10001, B11110, B10000, B10000, B10000}, //80 = 'P'
|
|
{ B01110, B10001, B10001, B10001, B10101, B10101, B01110}, //81 = 'Q'
|
|
{ B11110, B10001, B10001, B11110, B10100, B10010, B10001}, //82 = 'R'
|
|
{ B01110, B10001, B10000, B01110, B00001, B10001, B01110}, //83 = 'S'
|
|
{ B11111, B00100, B00100, B00100, B00100, B00100, B00100}, //84 = 'T'
|
|
{ B10001, B10001, B10001, B10001, B10001, B10001, B01110}, //85 = 'U'
|
|
{ B10001, B10001, B10001, B10001, B10001, B01010, B00100}, //86 = 'V'
|
|
{ B10001, B10001, B10001, B10001, B10101, B10101, B01010}, //87 = 'W'
|
|
{ B10001, B10001, B01010, B00100, B01010, B10001, B10001}, //88 = 'X'
|
|
{ B10001, B10001, B01010, B00100, B00100, B00100, B00100}, //89 = 'Y'
|
|
{ B11111, B00001, B00010, B00100, B01000, B10000, B11111}, //90 = 'Z'
|
|
{ B10000, B10000, B10000, B10010, B01010, B00110, B11110}, //flecha = 35
|
|
};
|
|
|
|
byte espacio[7] = { B00000, B00000, B00000, B00000, B00000, B00000, B00000}; //32 = ' '
|
|
|
|
byte sonrisa[7] = { B00000, B01110, B10001, B00000, B01010, B01010, B00000}; //Sonrisa
|
|
|
|
byte test[7] = { B11111, B11111, B11111, B11111, B11111, B11111, B11111};//0x01
|
|
|
|
// Holds the current colour level for each of the buttons
|
|
int levelW[64] = {
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
|
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
// Variables for interpreting the serial commands
|
|
|
|
byte command[64] = {
|
|
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
|
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
|
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32,
|
|
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32};
|
|
|
|
byte command_ant = 32;
|
|
byte finish = 1;
|
|
|
|
byte count = 0;
|
|
byte count_vis = 2;
|
|
boolean ok=false;
|
|
|
|
unsigned long time=0;
|
|
|
|
// For interrupt timing; needed only to do intermediate clock speeds
|
|
/* Divide interrupt frequency by a factor of FREQ. It is preferable to keep
|
|
FREQ as small as possible, and control the frequency of the interrupts
|
|
using the hardware clock. Setting it to 1 disables this entirely, which,
|
|
if it works, is ideal; this should be the same as commenting out the
|
|
"#define FREQ" statement entirely.
|
|
*/
|
|
#define FREQ 100 // How many interrupts occur before the serial commands are read
|
|
#if FREQ > 1
|
|
byte int_counter = 0;
|
|
#endif
|
|
|
|
// Transfer a character out over hardware SPI
|
|
char spi_transfer(volatile byte data)
|
|
{
|
|
SPDR = data; // Start the transmission
|
|
while (!(SPSR & (1<<SPIF))) // Wait the end of the transmission
|
|
{
|
|
};
|
|
return SPDR; // return the received byte
|
|
}
|
|
|
|
ISR(TIMER2_OVF_vect) {
|
|
sei(); //Reenable global interrupts, otherwise serial commands will get dropped
|
|
#if FREQ > 1
|
|
if(++int_counter == FREQ){ // Only do this once every FREQ-th interrupt
|
|
int_counter = 0;
|
|
#endif //FREQ
|
|
if(Serial.available()){
|
|
|
|
int val = Serial.read();
|
|
|
|
if ((val==13)||(val==10)||(val==0x01)||(val==0x02)||(val==0x03)||(val==0x04)||(val==0x05)||(val==44)) //INTRO
|
|
{
|
|
if(val==13)
|
|
{
|
|
for(int i = 1; i<=count; i++) command[i]=32;
|
|
for(int i = 1; i<=count; i++) EEPROM.write(address+i, 32); // grabamos en eeprom el caracter
|
|
count=0;
|
|
EEPROM.write(address, count);
|
|
|
|
Serial.print(val,BYTE);
|
|
ok=false;
|
|
finish=0;
|
|
modo=8;
|
|
|
|
count_vis=1;
|
|
time=millis();
|
|
}
|
|
else if(val==0x01)
|
|
{
|
|
Serial.print(val,BYTE);
|
|
count=0;
|
|
EEPROM.write(address, count);
|
|
finish=0;
|
|
modo=9;
|
|
}
|
|
else if(val==44)
|
|
{
|
|
ok=false;
|
|
Serial.print(val,BYTE);
|
|
if (count==0) count=count+2;
|
|
else count=count+1;
|
|
EEPROM.write(address, count);
|
|
}
|
|
else if(val==0x02)
|
|
{
|
|
intensidad=63;
|
|
EEPROM.write(65, intensidad);
|
|
Serial.print(val,BYTE);
|
|
}
|
|
else if(val==0x03)
|
|
{
|
|
intensidad=126;
|
|
EEPROM.write(65, intensidad);
|
|
Serial.print(val,BYTE);
|
|
}
|
|
else if(val==0x04)
|
|
{
|
|
intensidad=189;
|
|
EEPROM.write(65, intensidad);
|
|
Serial.print(val,BYTE);
|
|
}
|
|
else if(val==0x05)
|
|
{
|
|
intensidad=252;
|
|
EEPROM.write(65, intensidad);
|
|
Serial.print(val,BYTE);
|
|
}
|
|
}
|
|
else if (ok) Serial.print(val,BYTE); //tunel
|
|
else if ((val==32)||((val<58)&&(val>=48))||((val<78)&&(val>=65))||((val<92)&&(val>=78))||((val<110)&&(val>=97))||((val<123)&&(val>=110)))
|
|
{
|
|
if (count==0)
|
|
{
|
|
count=count+1;
|
|
EEPROM.write(address, count);
|
|
}
|
|
command[count]=val;
|
|
EEPROM.write(address+count, val); // grabamos en eeprom el caracter
|
|
ok=true;
|
|
}
|
|
}
|
|
// If the serial buffer is getting too close to full, keep executing the parsing until it falls below a given level
|
|
// This might cause flicker, or even dropped messages, but it should prevent a crash.
|
|
#if FREQ > 1
|
|
}
|
|
#endif //FREQ
|
|
}
|
|
|
|
void setup() {
|
|
|
|
|
|
// Start the serial port
|
|
Serial.begin(BAUD);
|
|
delay(10);
|
|
|
|
//Setup data directions, and set everything to the correct initial levels,
|
|
// For TLC5940
|
|
pinMode(VPRG, OUTPUT);
|
|
pinMode(SIN, OUTPUT);
|
|
pinMode(SCLK, OUTPUT);
|
|
pinMode(XLAT, OUTPUT);
|
|
pinMode(BLANK, OUTPUT);
|
|
pinMode(DCPRG, OUTPUT);
|
|
pinMode(GSCLK, OUTPUT);
|
|
pinMode(MISO, INPUT);
|
|
pinMode(SS,OUTPUT);
|
|
digitalWrite(SS,HIGH); //disable device
|
|
digitalWrite(SIN, LOW);
|
|
digitalWrite(SCLK, LOW);
|
|
digitalWrite(XLAT, LOW);
|
|
digitalWrite(VPRG, LOW);
|
|
digitalWrite(BLANK, HIGH);
|
|
digitalWrite(GSCLK, HIGH);
|
|
digitalWrite(DCPRG, LOW); // USE EEPROM DC register if LOW
|
|
|
|
//////// LECTURA DE EEPROM ////////
|
|
intensidad = EEPROM.read(65);
|
|
count = EEPROM.read(address);
|
|
//delay(500);
|
|
/*Serial.print(" EL CONTADOR ESTA A ");
|
|
Serial.print(count, DEC);
|
|
Serial.print(" LOS NUMEROS SON ");*/
|
|
|
|
if (count>63) count=63;
|
|
|
|
for(int i = 1; i<=count; i++)
|
|
{
|
|
command[i] = EEPROM.read(address+i);
|
|
/*Serial.print(command[i],BYTE);
|
|
Serial.print(0x20,BYTE); */
|
|
}
|
|
//Serial.print(0x0D,BYTE);
|
|
|
|
if (count>=1)
|
|
{
|
|
if (command[1]==32) modo=1; //Espacio
|
|
else if ((command[1]<58)&&(command[1]>=48)) modo=2; //Numeros
|
|
else if ((command[1]<78)&&(command[1]>=65)) modo=3; //Letras de la 'A' a la 'M'
|
|
else if ((command[1]<92)&&(command[1]>=78)) modo=5; //Letras de la 'N' a la 'Z' y la flecha
|
|
else if ((command[1]<110)&&(command[1]>=97)) modo=4; //Letras de la 'a' a 'm'
|
|
else if ((command[1]<123)&&(command[1]>=110)) modo=6; //Letras de la 'n' a la 'z'
|
|
else modo=7;
|
|
}
|
|
else modo=8;
|
|
|
|
byte gira_prov[7] = { B00000, B00000, B00000, B00000, B00000, B00000, B00000};
|
|
|
|
for(int j = 0; j<10; j++){
|
|
for(int i = 0; i<7; i++){
|
|
gira_prov[i]=numero[j][6-i];
|
|
}
|
|
for(int i = 0; i<7; i++){
|
|
numero[j][i]=gira_prov[i];
|
|
}
|
|
}
|
|
|
|
for(int j = 0; j<13; j++){
|
|
for(int i = 0; i<7; i++){
|
|
gira_prov[i]=caracterA[j][6-i];
|
|
}
|
|
for(int i = 0; i<7; i++){
|
|
caracterA[j][i]=gira_prov[i];
|
|
}
|
|
}
|
|
|
|
for(int j = 0; j<14; j++){
|
|
for(int i = 0; i<7; i++){
|
|
gira_prov[i]=caracterB[j][6-i];
|
|
}
|
|
for(int i = 0; i<7; i++){
|
|
caracterB[j][i]=gira_prov[i];
|
|
}
|
|
}
|
|
|
|
//Setup the Hardware SPI registers
|
|
// SPCR = 01010000
|
|
//interrupt disabled,spi enabled,msb 1st,master,clk low when idle,
|
|
//sample on leading edge of clk,system clock/4 (fastest)
|
|
byte clr;
|
|
SPCR = (1<<SPE)|(1<<MSTR);
|
|
clr=SPSR;
|
|
clr=SPDR;
|
|
delay(10);
|
|
|
|
TCCR2A = 0;
|
|
TCCR2B = 0<<CS22 | 1<<CS21 | 1<<CS20;
|
|
|
|
//Timer2 Overflow Interrupt Enable
|
|
TIMSK2 = 1<<TOIE2;
|
|
|
|
delay(10);
|
|
|
|
//Serial.print(13,BYTE);
|
|
|
|
// Run the startup animation
|
|
//startup();
|
|
|
|
time=millis();
|
|
|
|
}
|
|
|
|
void loop () {
|
|
|
|
if ((millis()-time)>=5000)
|
|
{
|
|
|
|
if (count_vis<count) count_vis=count_vis+1;
|
|
else count_vis=1;
|
|
|
|
//Serial.print(command[count_vis],BYTE);
|
|
//Serial.print(0x0D,BYTE);
|
|
|
|
if (command[count_vis]==32) modo=1; //Espacio
|
|
else if ((command[count_vis]<58)&&(command[count_vis]>=48)) modo=2; //Numeros
|
|
else if ((command[count_vis]<78)&&(command[count_vis]>=65)) modo=3; //Letras de la 'A' a la 'M'
|
|
else if ((command[count_vis]<92)&&(command[count_vis]>=78)) modo=5; //Letras de la 'N' a la 'Z' y la flecha
|
|
else if ((command[count_vis]<110)&&(command[count_vis]>=97)) modo=4; //Letras de la 'a' a 'm'
|
|
else if ((command[count_vis]<123)&&(command[count_vis]>=110)) modo=6; //Letras de la 'n' a la 'z'
|
|
else modo=7;
|
|
time=millis();
|
|
|
|
|
|
}
|
|
|
|
switch (modo) {
|
|
case 1: if (finish) {letra(espacio,espacio); modo=0;} break;
|
|
case 2: if (finish) {letra(numero[command[count_vis]-48],espacio); modo=0;} break;
|
|
case 3: if (finish) {letra(caracterA[command[count_vis]-65],espacio); modo=0;} break;
|
|
case 4: if (finish) {letra(caracterA[command[count_vis]-97],espacio); modo=0;} break;
|
|
case 5: if (finish) {letra(caracterB[command[count_vis]-78],espacio); modo=0;} break;
|
|
case 6: if (finish) {letra(caracterB[command[count_vis]-110],espacio); modo=0;} break;
|
|
case 7: if (finish) {letra(sonrisa,espacio); modo=0;} break;
|
|
case 8: letra(espacio,espacio); if (modo==8) modo=0; finish=1; break;
|
|
case 9: letra(test,espacio); if (modo==9) modo=0; finish=1; break;
|
|
}
|
|
makemagic();
|
|
|
|
}
|
|
|
|
void makemagic(){
|
|
setGreysW();
|
|
feedPorts();
|
|
}
|
|
|
|
void setGreysW() {
|
|
digitalWrite(BLANK, HIGH);
|
|
digitalWrite(XLAT,LOW);
|
|
for(int i = 21; i>=0; i--){
|
|
spi_transfer( (levelW[2*i+1] & 0x0FF0) >> 4 );
|
|
spi_transfer( ((levelW[2*i+1] & 0xF) << 4) | ((levelW[2*i] & 0x0F00) >> 8) );
|
|
spi_transfer( levelW[2*i] & 0xFF);
|
|
}
|
|
digitalWrite(XLAT,HIGH);
|
|
digitalWrite(XLAT,LOW);
|
|
digitalWrite(BLANK, LOW);
|
|
}
|
|
|
|
void feedPorts() {
|
|
// Clock for TLC5940's PWM
|
|
digitalWrite(BLANK, HIGH);
|
|
digitalWrite(BLANK, LOW); //=all outputs ON, start PWM cycle
|
|
for (int i=0; i<4096; i++) {
|
|
pulseGSCLK();
|
|
}
|
|
}
|
|
|
|
void pulseGSCLK() {
|
|
//ultra fast pulse trick, using digitalWrite caused flickering
|
|
PORTD |= 0x80 ; // bring pin 7 high, but don't touch any of the other pins in PORTB
|
|
//16 nanosecs is the min pulse width for the 5940, but no pause seems needed here
|
|
PORTD &= 0x7F; // bring pin 7 low without touching the other pins in PORTB
|
|
}
|
|
|
|
byte letra(byte let[7], byte let_ant[7]) {
|
|
byte letbool=0;
|
|
byte let_new[7] = { B00000, B00000, B00000, B00000, B00000, B00000, B00000};
|
|
|
|
for(byte j = 1; j <6; ++j){
|
|
for(byte h = 0; h <7; ++h){
|
|
let_new[h]=((0X1F&(let_ant[h]<<j))|(let[h]>>(5-j)));
|
|
}
|
|
letbool=0;
|
|
for(byte x = 0; x < 7; ++x){
|
|
for(byte y = 0; y <5; ++y){
|
|
if (0x01&let_new[letbool]>>y) levelW[remap[x][y]] = 16*intensidad;
|
|
else levelW[remap[x][y]] = 0;
|
|
}
|
|
++letbool;
|
|
}
|
|
for(int i = 0; i <20; ++i) makemagic();
|
|
}
|
|
}
|
|
|