Tecnologia vestible

Per començar Elements d'entrada Programació CircuitPython   Recursos CITCEA
Elements no electrònics Elements de sortida Programació Arduino    
Projectes Elements de control Dades pràctiques   Inici

NeoPixel Matrix

El NeoPixel Matrix és un conjunt de NeoPixel disposats en un rectangle.

El control dels NeoPixel de la matriu es fa des d'una única sortida digital del microcontrolador de manera que deixa totes les altres potes lliures per a altres funcions. A més, els NeoPixel Matrix es poden posar en cadena (connectant la sortida de l'un amb l'entrada del següent) tant amb NeoPixel Matrix com amb altres NeoPixel o NeoPixel Ring i això permet controlar individualment un nombre elevat de LED fent servir una única sortida. En la imatge següent veiem la matriu de vuit per vuit on el LED de dalt a l'esquerra és el 0. Aquest LED té el 1 a la dreta i el 8 a sota. La cantonada inferior dreta serà el LED 63.

NeoPixel Matrix  [SF]

Existeixen cristalls difusors per als NeoPixels.

Els borns de connexió del NeoPixel Matrix es veuen a la part superior de la figura següent. Per fer servir un NeoPixel Matrix cal connectar el born 5V al born positiu de l'alimentació, el born GND al negatiu de l'alimentació i el born DIN amb una sortida digital del microcontrolador. A la part inferior veiem els borns de sortida per si volem encadenar. Com podem veure, el disseny de la NeoPixel Matrix no està pensat per a tecnologia vestible ja que l'única forma fàcil de connectar els fils és soldant-los.

NeoPixel Matrix  [SF]

Es fabriquen NeoPixel Matrix RGB i RGBW en diferents formats. Per exemple 5⨯8 LED i 8⨯8 LED. En les que són RGBW sovint es pot escollir entre diferents tons de blanc.

També hi ha NeoPixel Matrix flexibles, com la de 8⨯8, la de 16⨯16 i la de 8⨯32.

Per fer sortir lletres o imatges en un NeoPixel Matrix cal una programació una mica més complexa que en altres casos perquè, no ho oblidem, estem actuant sobre molts LED simultàniament.

En el programa següent (per a la matriu de vuit per vuit) hem generat les figures que es mostren a les imatges que es mostren a continuació:

Sentit prohibit           Fletxa verda amunt

En el programa hem definit un vector de dues dimensions (matemàticament equival a una matriu) que contindrà les definicions dels quatre colors que fem servir (negre, vermell i blanc per a primer dibuix i negre i verd per al segon). El primer índexs ens diu quin dels quatre colors volem i el segon la component corresponent d'aquest color. També hem definit uns altres vectors de dues dimensions per guardar els dos símbols que volem dibuixar. El primer índex correspon a la filera i el segon a la columna. El valor que posem a cada posició d'aquesta matriu es correspon amb el color que volem mostrar en aquella posició. Fixem-nos que en el primer símbol hem posat els valors en forma matricial que ajuda a imaginar-se el que estem representant mentre que amb el segon hem optat per una disposició més compacta per estalviar espai.

Hem creat dues funcions. La primera posa a zero tots els índexs de tots els LED i, per tant, els apaga. La segona funció té com a paràmetre el símbol que volem representar i fa un repàs a les 64 posicions assignant a cada LED el valorque li correspon segons el que s'ha definit a la variable de colors.

El programa principal és molt senzill ja que només fa una alternança entre els dos símbols amb una pausa intermèdia amb els LED apagats.

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel cadena = Adafruit_NeoPixel(64, 6, NEO_GRB + NEO_KHZ800);
byte  colors[4][3]{
	{0,0,0},  // negre (apagat)
	{64,0,0},  // vermell
	{64,64,64},  // blanc
	{0,64,0}  //  verd
};
byte simbol1[8][8] = {
	{0,0,1,1,1,1,0,0},
	{0,1,1,1,1,1,1,0},
	{1,1,1,1,1,1,1,1},
	{1,2,2,2,2,2,2,1},
	{1,2,2,2,2,2,2,1},
	{1,1,1,1,1,1,1,1},
	{0,1,1,1,1,1,1,0},
	{0,0,1,1,1,1,0,0}
};
byte simbol2[8][8] = {{0,0,0,3,3,0,0,0},{0,0,3,3,3,3,0,0},{0,3,3,3,3,3,3,0},{3,3,3,3,3,3,3,3},
	{0,0,0,3,3,0,0,0},{0,0,0,3,3,0,0,0},{0,0,0,3,3,0,0,0},{0,0,0,3,3,0,0,0}};
void apaga() {
	for (int j = 0; j < 8; j++){  // fileres
		for (int k = 0; k < 8; k++){  // columnes
			int p = 8 * j + k;
			cadena.setPixelColor(p, 0,0,0);
		}
	}
	cadena.show(); // Actualitza
}
void mostra(byte car[8][8]) {
	for (int j = 0; j < 8; j++){  // fileres
		for (int k = 0; k < 8; k++){  // columnes
			byte pixel = car[j][k];
			int p = 8 * j + k;
			cadena.setPixelColor(p, colors[pixel][0],colors[pixel][1],colors[pixel][2]);
		}
	}
	cadena.show(); // Actualitza
}
void setup() {
	cadena.begin();  // Inicialitza els NeoPixels        
	cadena.show();
}
void loop() {
	mostra(simbol1);
	delay(1000);  // Espera un segon
	apaga();
	delay(1000);  // Espera un segon
	mostra(simbol2);
	delay(1000);  // Espera un segon
	apaga();
	delay(1000);  // Espera un segon
}

Ara anem a fer un segon programa en el que mostrarem lletres. Atès que normalment els textos solen ser d'un sol color, hem optat per definir les lletres de manera més compacta. Per a cada lletra farem servir 8 bytes i cada bit d'aquests bytes definira un dels píxels de la lletra. El nostre vector lletres té dues dimensions, la primera correspon a cada una de les lletres que farem servir (en el nostre cas (C, I, T, E, A i l'espai) i la segona a cada una de les fileres de cada lletra. Els elements d'aquest vector són bytes definints bit a bit, amb una B seguida d'un 0 o un 1 segons desitgem.

També hem definit un vector colors on guardarem les tres components de cada un dels cinc colors que farem servir i un vector nom on hi ha el text que volem escriure. Cada element del vector nom és l'índex de la lletra que correspon. En aquest cas, escriurem "ETSEIB ".

L'element principal del nostre exemple és la funció mostra que és l'encarregada de fer aparèixer les lletres a la matriu de leds. A aquesta funció li hem d'indicar el text que volem escriure, la seva llargada i el color amb el que el volem mostrar. En el primer bucle (índex i) recorrem cada una de les lletres. En el segon bucle (índex j) creem una filera i en el tercer bucle (índex k) definim el bit corresponent. Com no podem adreçar els bits, fem servir una màscara. La funció i (and, &) amb una variable que només té un bit activat deixa activat el bit corresponent de la variable comparada (en aquest cas, filera) i desactivats tots els altres. Això farà que el resultat pixel sigui 0 si el bit estava desactivat i un altre valor si estava activat. ELs activats els pintarem del color indicat i els desactivats els apagarem. Començarem aquest bucle amb el bit 1 a l'esquerra i el desplaçarem un lloc a la dreta a cada iteració.

El programa principal és molt senzill. Només fa un bucle en el que va cridant a la funció mostra amb un color diferent dels cinc definits.

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel cadena = Adafruit_NeoPixel(64, 6, NEO_GRB + NEO_KHZ800);
byte nom[] = {1,2,3,1,4,5,0};  // "ETSEIB "
byte  colors[5][3]{
	{255,0,0},  // vermell
	{0,255,0},  //  verd
	{0,0,255},  // blau
	{255,255,0},  // groc
	{255,255,255}  // blanc
};  
byte lletres[6][8] = {
	{B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000}, // 0  espai
	{B00111110,B00100000,B00100000,B00111100,B00100000,B00100000,B00111110,B00000000}, // 1  lletra E
	{B00111110,B00001000,B00001000,B00001000,B00001000,B00001000,B00001000,B00000000}, // 2  lletra T
	{B00011110,B00100000,B00100000,B00011100,B00000010,B00000010,B00111100,B00000000}, // 3  lletra S
	{B00011100,B00001000,B00001000,B00001000,B00001000,B00001000,B00011100,B00000000}, // 4  lletra I
	{B00111100,
	 B00100010,
	 B00100010,
	 B00111100,
	 B00100010,
	 B00100010,
	 B00111100,
	 B00000000}, // 5  lletra B
};
void mostra(byte text[], int llarg, byte c) {
	for (int i = 0; i < llarg; i++){  
		byte lletraAct = text[i];
		for (int j = 0; j < 8; j++){
			byte filera = lletres[lletraAct][j];
			byte mascara = B10000000;
			for (int k = 0; k < 8; k++){
				byte pixel = filera & mascara;
				int p = 8 * j + k;
				if (pixel == 0) {
					cadena.setPixelColor(p, 0, 0, 0);	// Píxel apagat
				} else {
					cadena.setPixelColor(p,colors[c][0],colors[c][1],colors[c][2]);
				}						// Píxel de color
				mascara = mascara >> 1;
			}
		}
		cadena.show(); // Actualitza
		delay(1000);  // Espera un segon
	}
}
void setup() {
	cadena.begin();  // Inicialitza els NeoPixels        
	cadena.show();
}
void loop() {
	for (int col = 0; col < 5; col++){  
		mostra(nom, sizeof(nom), col);	// sizeof() ens dóna la mida en bytes
						// Atès que el nostre vector és de bytes
						// coincidirà amb el nombre d'elements 
	}          
}

Un efecte més espectacular és el de fer rodar les lletres quan es mostra el missatge. Això és el que fa el programa següent que és una nova versió de l'anterior en la que hem modificat la funció mostra.

Quan les lletres roden, l'inici i el final del missatge són crítics. Per evitar que es vegi aparèixer la primera lletra de cop, la funció comença afegint un espai en blanc al començament del text. Es podria haver advertit a l'usuari que ho fes però és més elegant que l'usuari posi el text que vulgui i que sigui el programa qui ho gestioni.

Igual com en el cas anterior, tenim un primer bucle per a les lletres del text que volem mostrar. Però ara llegirem dues lletres, la que toca ara i la següent. En cas que la que toca ara sigui la darrera, posarem un espai per a la següent. Això ens arreglarà el problema del final del text.

El bucle de fileres l'hem posat dins d'un altre bucle que recorre les vuit columnes de la matriu. En la primera iteració d'aquest bucle es mostrarà el caràcter actual sencer i a les següents un tros de l'actual i la resta del següent. Per això a cada iteració farem rodar els bits del caràcter actual cap a l'esquerra el nombre de posicions que toqui i també farem rodar el caràcter següent cap a la dreta la resta de posicions fins a 8. Amb la funció o (or, |) combinarem els trossos dels dos caràcters per crear el símbol que mostrarem a la matriu de LED. Ara el temps d'espera és menor ja que correspon a una columna i no a una lletra completa.

#include <Adafruit_NeoPixel.h>
Adafruit_NeoPixel cadena = Adafruit_NeoPixel(64, 6, NEO_GRB + NEO_KHZ800);
byte nom[] = {1,2,3,1,4,5,0};  // "ETSEIB "
byte  colors[5][3]{
	{255,0,0},  // vermell
	{0,255,0},  //  verd
	{0,0,255},  // blau
	{255,255,0},  // groc
	{255,255,255}  // blanc
};  
byte lletres[6][8] = {
	{B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000,B00000000}, // 0  espai
	{B00111110,B00100000,B00100000,B00111100,B00100000,B00100000,B00111110,B00000000}, // 1  lletra E
	{B00111110,B00001000,B00001000,B00001000,B00001000,B00001000,B00001000,B00000000}, // 2  lletra T
	{B00011110,B00100000,B00100000,B00011100,B00000010,B00000010,B00111100,B00000000}, // 3  lletra S
	{B00011100,B00001000,B00001000,B00001000,B00001000,B00001000,B00011100,B00000000}, // 4  lletra I
	{B00111100,
	 B00100010,
	 B00100010,
	 B00111100,
	 B00100010,
	 B00100010,
	 B00111100,
	 B00000000}, // 5  lletra B
};
void matriu(byte simbol[8], byte c) {
	for (int j = 0; j < 8; j++){
		byte filera = simbol[j];
		byte mascara = B10000000;
		for (int k = 0; k < 8; k++){
			byte pixel = filera & mascara;
			int p = 8 * j + k;
			if (pixel == 0) {
				cadena.setPixelColor(p, 0, 0, 0); // Píxel apagat
			} else {
				cadena.setPixelColor(p,colors[c][0],colors[c][1],colors[c][2]);
			}           // Píxel de color
			mascara = mascara >> 1;
		}
	}
}
void mostra(byte tex[], int llar, byte color) {
	int llarg = llar + 1;
	byte text[llarg];
	text[0] = 0;
	for (int i = 0; i < llar; i++){
		text[i+1] = tex[i];
	}
	byte lletraAct;
	byte lletraSeg;
	byte caracter[8];
	for (int car = 0; car < llarg; car++){  // Bucle per a les lletres
		lletraAct = text[car];
		if (car == llarg - 1) {       
			lletraSeg = 0;
		} else {
			lletraSeg = text[car+1];
		}
		for (int colum = 0; colum < 8; colum++){  // Bucle per al desplaçament
			for (int j = 0; j < 8; j++){  // Bucle per a les fileres
				byte filaAct = lletres[lletraAct][j];
				byte filaSeg = lletres[lletraSeg][j];
				int resta = 8 - colum;
				byte esquerra = filaAct << colum;
				byte dreta = filaSeg >> resta;
				caracter[j] = esquerra | dreta;
			}
			matriu(caracter, color);
			cadena.show(); // Actualitza
			delay(100);  // Espera 0,1 s
		}
	}
}
void setup() {
	cadena.begin();  // Inicialitza els NeoPixels        
	cadena.show();
}
void loop() {
	for (int col = 0; col < 5; col++){  
		mostra(nom, sizeof(nom), col);	// sizeof() ens dóna la mida en bytes
						// Atès que el nostre vector és de bytes
						// coincidirà amb el nombre d'elements 
	}          
}

 

 

 

En aquest web, les fotografies marcades amb [AF] són del web d'Adafruit, les marcades amb [SF] del web d'Sparkfun i les marcades amb [AU] del web d'Arduino.

 

 

 

 

 

 

 

 

 

 

Llicència de Creative Commons
Aquesta obra d'Oriol Boix està llicenciada sota una llicència no importada Reconeixement-NoComercial-SenseObraDerivada 3.0.