Lab_interaccio/2013/Cibernarium_2013/Cibernarium_2013.ino

369 lines
13 KiB
Arduino
Raw Permalink Normal View History

2025-02-25 21:29:42 +01:00
#include <Arduino.h>
#include "TimerOne.h"
#include <EEPROM.h>
#define BAUD 9600
//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 id 0
// start reading from the first byte (address 0) of the EEPROM
int address = 300;
int vuelta = 0;
#define intensidad 252 //0 - 255
const byte remap[7][5] = { //Mapeo de los leds
{0,7,18,25,36},
{1,8,19,26,37},
{2,9,20,27,38},
{3,10,21,32,39},
{4,11,22,33,40},
{5,16,23,34,41},
{6,17,24,35,42},
};
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, B01010, B01010, B00000, B10001, B01110, 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] = {
' ', ' ', 'B', 'E', 'N', 'V', 'I', 'N', 'G', 'U', 'D', 'E', 'S', ' ', ' ', ' ',
' ', 'B', 'E', 'N', 'V', 'I', 'N', 'G', 'U', 'T', 'S', ' ', 'A', 'L', ' ', ' ',
' ', ' ', 'C', 'I', 'B', 'E', 'R', 'N', 'A', 'R', 'I', 'U', 'M', ' ', ' ', ' ',
' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' '};
byte finish = 1;
byte count = 0x00;
boolean save=false;
boolean sincro=false;
boolean bloqueo=false;
boolean update = false;
unsigned long time=0;
// 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
}
void timerIsr(){
sei(); //Reenable global interrupts, otherwise serial commands will get dropped
if(Serial.available()){
byte val = Serial.read();
if ((val=='\r')||(val=='\n'))
{
if(val=='\r')
{
Serial.write(val);
count = 0x00;
vuelta = 0x00;
command[0] = ' ';
bloqueo = false;
save = true;
}
}
#if id == 0
else if ((val==' ')||((val<='9')&&(val>='0'))||((val<'N')&&(val>='A'))||((val<='Z')&&(val>='N'))||((val<'n')&&(val>='a'))||((val<='z')&&(val>='n')))
{
command[count] = val;
count++;
bloqueo = false;
save = true;
update = true;
}
#else
else if (val== (id + 0x0F)) sincro = true;
else if (sincro) {command[0] = val; bloqueo = false; sincro = false;}
else Serial.write(val);
#endif
}
// 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.
}
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 ////////
#if id == 0
delay(100);
//
EEPROM.write(address, 48);
for (int i = 0; i<48; i++) EEPROM.write(address + 1 + i, command[i]); // grabamos en eeprom el caracter
count = EEPROM.read(address);
if (count>63) count = 63;
//count = EEPROM.read(address);
//count = 5;
for(int i = 0; i<count; i++) command[i] = EEPROM.read(address + 1 + i);
#endif
//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);
Timer1.initialize(500); // set a timer of length 1000000 microseconds (or 1 sec - or 1Hz)
Timer1.attachInterrupt( timerIsr ); // attach the service routine here
delay(10);
time=millis();
}
#if id == 0
int limit = 16;
#else
int limit = 0;
#endif
void loop () {
//letra(caracterA[2], espacio);
//Serial.println(caracterA[2][1], BIN);
//for (int i =0; i<100; i++) makemagic();
makemagic();
#if id == 0
if (save)
{
Timer1.stop(); // set a timer of length 1000000 microseconds (or 1 sec - or 1Hz)
//Serial.println(count);
EEPROM.write(address, count);
for (int i = 0; i<count; i++) EEPROM.write(address + 1 + i, command[i]); // grabamos en eeprom el caracter
save = false;
Timer1.initialize(500); // set a timer of length 1000000 microseconds (or 1 sec - or 1Hz)
}
if (((millis()-time)>=5000)||(update))
{
update = false;
//for (int i = 1; i<count; i++) Serial.write(command[i]);
bloqueo = false;
for (int i = 1; i<limit; i++)
{
Serial.write(0x0F + i);
if (((vuelta*limit) + i) >= count) Serial.write(' ');
else Serial.write(command[(vuelta*limit) + i]);
}
// Serial.println();
}
#endif
if (!bloqueo)
{
time=millis();
if (command[limit*vuelta]==32) modo=1; //Espacio
else if ((command[limit*vuelta]<='9')&&(command[limit*vuelta]>='0')) modo=2; //Numeros
else if ((command[limit*vuelta]<'N')&&(command[limit*vuelta]>='A')) modo=3; //Letras de la 'A' a la 'M'
else if ((command[limit*vuelta]<='Z')&&(command[limit*vuelta]>='N')) modo=5; //Letras de la 'N' a la 'Z' y la flecha
else if ((command[limit*vuelta]<'n')&&(command[limit*vuelta]>='a')) modo=4; //Letras de la 'a' a 'm'
else if ((command[limit*vuelta]<='z')&&(command[limit*vuelta]>='n')) modo=6; //Letras de la 'n' a la 'z'
//else modo=7;
switch (modo) {
case 1: if (finish) {letra(espacio,espacio); modo=0;} break;
case 2: if (finish) {letra(numero[command[limit*vuelta] - '0'],espacio); modo=0;} break;
case 3: if (finish) {letra(caracterA[command[limit*vuelta] - 'A'],espacio); modo=0;} break;
case 4: if (finish) {letra(caracterA[command[limit*vuelta] - 'a'],espacio); modo=0;} break;
case 5: if (finish) {letra(caracterB[command[limit*vuelta] - 'N'],espacio); modo=0;} break;
case 6: if (finish) {letra(caracterB[command[limit*vuelta] - 'n'],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;
}
bloqueo = true;
int n = 0;
if (count > 3*limit) n = 3;
else if (count > 2*limit) n = 2;
else if (count > limit) n = 1;
else n = 0;
if (vuelta < n) vuelta++;
else vuelta = 0;
}
}
void makemagic(){
setGreysW1();
feedPorts();
setGreysW2();
feedPorts();
}
void setGreysW1() {
digitalWrite(BLANK, HIGH);
digitalWrite(XLAT,LOW);
for(int i = 21; i>=0; i--){
spi_transfer(0x00);
spi_transfer( (0x00) | ((levelW[2*i] & 0x0F00) >> 8) );
spi_transfer( levelW[2*i] & 0xFF);
}
digitalWrite(XLAT,HIGH);
digitalWrite(XLAT,LOW);
digitalWrite(BLANK, LOW);
}
void setGreysW2() {
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) | (0x00) );
spi_transfer(0x00);
}
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){ //Actualizacion de los leds
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;
}
//Serial.println(let_new[letbool], BIN);
++letbool;
}
for(int i = 0; i <20; ++i) makemagic();
}
}
byte letraWrite(byte let[7]) {
byte letbool=0;
letbool=0;
for(byte x = 0; x < 7; ++x){ //Actualizacion de los leds
for(byte y = 0; y <5; ++y){
if (0x01&let[letbool]>>y) levelW[remap[x][y]] = 16*intensidad;
else levelW[remap[x][y]] = 0;
}
++letbool;
}
for(int i = 0; i <20; ++i) makemagic();
}