La configuration matérielle pour un affichage de PoV est assez simple, mais cette instructable contient le code qui définit l’affichage peut être commandé et programmé facilement via la connexion série, paramètres d’affichage peuvent être enregistrés afin qu’ils sont automatiquement chargés et exécutés lorsque mis sous tension d’une batterie.
Vous voulez un Conseil de Microcontrôleur AVR Arduino, comme Uno, Nano ou mini. Environ 10 LEDs et 10 résistances d’environ 100 à 220 ohms.
Pour notre exemple, nous supposerons un écran LED 10. Fil de la LED en série avec une résistance aux broches d’e/s numériques 3-10 et les disposer dans une ligne droite.
Charger le croquis ci-joint.
À partir de la série monitor (ou l’émulateur de terminal), tapez h pour obtenir le menu aide. Cela montrera plusieurs commandes.
Ma classe de lecteur série compresse les espaces blancs, ainsi vous voudrez utiliser. pour représenter « off » dans les paramètres de la ligne. Voir le Quelab.dat exemple ligne paramètre d’entrée fichier joint. Les lignes de ce fichier peuvent être coupés et collés dans un émulateur de terminal pour définir le message de PoV.
Une fois votre affichage souhaité a été chargé, utilisez le s) commande pour enregistrer ses paramètres d’EEPROM pour être utilisé à la prochaine remise à zéro.
int dummy=0; // this is to force sketch to put arduino include here #define MODE_UNKNOWN 0 #define MODE_PoV 1 #define MODE_RANDOM 2 #define MODE_CYLON 3 #define MAX_COLS 96 #define SERIAL_BUF_LEN (MAX_COLS+15) #include SerialLineBuffer LineBuf; struct { short nCols; // no. columns in buffer short spaceCols; // no. columns "space" time before repeat or reverse short mode; // MODE_ code from above short cylonCols; // no. cols of time for each cylon flash int colTime; // milliseconds/column int misc[3]; // reserved for future use short disp[MAX_COLS]; // display flags } State; // These are the DI/O pins used for the display #define NPINS 10 int ledPins[NPINS] = {12,11,10,9,8,7,6,5,4,3}; #include void loadState() { int n = sizeof(State); byte *bp = (byte *)(&State); for(int i=0; i < n; i++, bp++) *bp = EEPROM.read(i); if (!validState()) initState(); } void saveState() { int n = sizeof(State); byte *bp = (byte *)(&State); for(int i=0; i < n; i++, bp++) EEPROM.write(i,*bp); } // set state to a reasonable default void initState() { State.nCols = 2; State.spaceCols = 1; State.cylonCols = 10; State.mode = MODE_PoV; State.colTime = 10; // ms for (int i=0; i < MAX_COLS; i++) State.disp[i] = (i&1)?0x5555:0x2aaa; saveState(); } void setup() { int i; for (i=0;i { pinMode(ledPins[i],OUTPUT); } pinMode(13,OUTPUT); // use on-board LED // restore state from EEPROM loadState(); Serial.begin(9600); } void loop() { checkCommand(); int i,dt,k; dt = State.colTime; switch (State.mode) { case MODE_CYLON: dt *= State.cylonCols; for (i=0; i < NPINS; i++) { digitalWrite(ledPins[i],HIGH); delay(dt); digitalWrite(ledPins[(i+NPINS-1)%NPINS],LOW); delay(dt); } for (i=NPINS-2; i >= 0; i--) { digitalWrite(ledPins[i],HIGH); delay(dt); digitalWrite(ledPins[(i+1)%NPINS],LOW); delay(dt); } break; case MODE_PoV: for (i=0; i < State.nCols; i++) { short mask=1; for (k=0; k < NPINS; k++, mask <<= 1) digitalWrite(ledPins[k],(mask & State.disp[i])?HIGH:LOW); } for (k=0; k < NPINS; k++) digitalWrite(ledPins[k],LOW); delay(State.spaceCols*dt); break; default: // random default { dt *= 10; k = random(100); int lvl = (k<50)?LOW:HIGH; int j = random(NPINS); digitalWrite(ledPins[j],lvl); delay(dt); } } digitalWrite(13,digitalRead(13)?LOW:HIGH); // toggle heartbeat } // poll for commands from serial port void checkCommand() { short mask; if (!LineBuf.isComplete()) return; char key = lowCase(*(LineBuf.get())); switch(key) { //short mask; //int k; //char *b; case 'h' : Serial.println(" h) help (print this message)"); Serial.println(" s) save state"); Serial.println(" r) random lights mode"); Serial.println(" c) cylon mode"); Serial.println(" p) PoV sign mode"); Serial.println(" n) no. cols to display"); Serial.println(" t) col time, ms"); Serial.println(" b) blank cols between repeat"); Serial.println(" i) re-Initialize state"); Serial.print( " Lx) Set pattern for line x, 0<=x<="); Serial.println(NPINS); break; case 's' : saveState(); break; case 'r' : State.mode = MODE_RANDOM; break; case 'p' : State.mode = MODE_PoV; break; case 'c' : State.mode = MODE_CYLON; break; case 'i' : initState(); break; case 'n' : State.nCols =nextInt(LineBuf.get()+1); break; case 't' : State.colTime =nextInt(LineBuf.get()+1); break; case 'b' : State.spaceCols=nextInt(LineBuf.get()+1); break; case 'l' : { char *b = LineBuf.get()+1; int k = ((int)(*b)) - ((int)'0'); if ((k<0) || (k > 15)) break; b++; short mask = (short)(1< for (int i=0; i < State.nCols; i++, b++) { if (isOn(*b)) State.disp[i] |= mask; else State.disp[i] &= ~mask; } break; } default : Serial.print("Unrecognized Command : <"); Serial.print(LineBuf.get()); Serial.println(">"); Serial.println("Send command h for help."); } printState(); printMsg(); } void printState() { Serial.print(State.nCols); Serial.print(" Columns "); Serial.print(State.spaceCols); Serial.print(" "); Serial.print(State.colTime); Serial.println("ms/col"); Serial.flush(); } void printMsg() { int i,k; Serial.println(); for (i=0; i < State.nCols; i++) Serial.print("-"); short mask=1; for(k=0; k < NPINS; k++, mask <= 1) { for (i=0; i < State.nCols; i++) Serial.print(State.disp[k]&mask?"X":" "); Serial.println("|"); } Serial.println(); for (i=0; i < State.nCols; i++) Serial.print("-"); Serial.println(); Serial.flush(); } // parse next int from a string int nextInt(const char *s) { const char *c = s; int val = 0; for(;;) { int k = ((int)(*c)) - ((int)'0'); if ((k<0)||(k>9)) return val; val *= 10; val += k; c++; } } bool isOn(const char c) { if ((c=='0') || (c=='.') || (c==' ') || (c==0)) return false; //if ((c=='1')||(lowCase(c)=='x')) return true; return true; } bool validState() { // check for silly state, set to default if inconsistent if ((State.mode <= 0) || (State.mode > 3) || (State.nCols< 1) || (State.nCols>MAX_COLS)) return false; if ((State.spaceCols < 1) || (State.spaceCols > 10*MAX_COLS)) return false; if ((State.colTime < 1) || (State.colTime > 10000)) return false; if ((State.cylonCols < 1) || (State.cylonCols > 10000)) return false; return true; }
---ioUtil.h
class SerialLineBufferPrivates; class SerialLineBuffer { public: SerialLineBuffer(); //~SerialLineBuffer(); bool isComplete(); // reads from serial, return true if 0 or EOLN void clear(); void begin(); int length() const; int maxLength() const; char *get(); // retrieve current buffer and clear char buf[SERIAL_BUF_LEN+1]; protected: int _maxLength, _len; bool _complete; private: //class SerialLineBufferPrivates *Priv; }; char lowCase(const char a); int caseCmp(const char a0, const char b0); char *extractKey(char *cmdStr, char **val); bool keyMatch(const char *key, const char *key1);
---ioUtil.cpp
#include #define NULL 0 // don't want to depend on ctype.h, just for this! bool isBlank(int c) { if(c == 7) return(false); // bell return( (c <= ' ') || (c > '~') ); } #if defined(ARDUINO) && ARDUINO >= 100 #include #warning ARDUINO #else #error ARDUINO not >= 100 #include #endif void SerialLineBuffer::begin() { _maxLength = SERIAL_BUF_LEN; // AVR dynamic mem is tricky _len = 0; _complete = false; } SerialLineBuffer::SerialLineBuffer() { begin(); } bool isTerminator(int c) { if (c == 0) return(true); if (c == ';') return(true); // sending \n to serial is tricky. accept this too. //if ((c=='\n') || (c=='\r') || (c=='\m')) return(true); if ((c>=10) && (c<=13)) return(true); // \r, \n, form feed, vert tab return(false); } /// read from serial, return true if 0 or EOLN bool SerialLineBuffer::isComplete() { if (_complete) return(true); // don't read more until this line is consumed // add characters from serial while(Serial.available() > 0) { int nextByte = Serial.read(); //Serial.print("Got ");Serial.println(nextByte); if ((nextByte < 0) || (nextByte >= 256)) return(_complete); if (isTerminator(nextByte)) { //Serial.print("terminator ");Serial.println(nextByte); buf[_len] = 0; _complete = (_len > 0); return(_complete); } if (isBlank(nextByte)) { //Serial.print("blank ");Serial.println(nextByte); if (_len > 0) // ignore leading whitespace { if (buf[_len-1] != ' ') // compact space to 1 space { buf[_len++] = ' '; // convert all space to ' ' } } } else { buf[_len++] = (char)nextByte; } // don't allow overflow if (_len >= _maxLength) { Serial.println("\nOverflow. truncating command string"); _complete = true; } } return(_complete); } void SerialLineBuffer::clear() { _len = 0; _complete = false; } int SerialLineBuffer::length() const { return(_len); } int SerialLineBuffer::maxLength() const { return(_maxLength); } /// retrieve current buffer and clear char *SerialLineBuffer::get() { buf[_len]=0; clear(); return(buf); } //----------------------------------------------------------- /// split a keyword-value pair string into a key string and value string const char nullChar = 0; // static is scary on AVR char *extractKey(char *cmdStr, char **val) { *val = (char *)&nullChar; if (cmdStr == NULL) return(NULL); char *key = cmdStr; while (*key) // process comments { if (*key == '#') *key=0; // comment else key++; } key = cmdStr; while(*key && isBlank(*key)) key++; // trim leading space *val = key; while(**val && !isBlank(**val)) *val += 1; // skip key **val = 0; *val += 1; while(**val && isBlank(**val)) *val += 1; // skip whitespace return(key); } char lowCase(const char a) { if ((a >= 'A') && (a <= 'Z')) { int sft = ((int)'a') - ((int)'A'); int b = (int)a + sft; return((char)b); } return(a); } int caseCmp(const char a0, const char b0) { char a = lowCase(a0); char b = lowCase(b0); if (a < b) return(-1); return((a>b)?1:0); } bool keyMatch(const char *key0, const char *key1) { //Serial.print("keyMatch(");Serial.print(key0);Serial.print(",");Serial.print(key1);Serial.print(")="); while(*key0 || *key1) { if (caseCmp(*key0, *key1)) { //Serial.println("false"); return(false); } if (*key0) key0++; if (*key1) key1++; } //Serial.println("true"); return(true); }
---Exemple de données d’entrée
L0..Q.............l......b.... L1.QQQ............l......b.... L2Q...Q...........l......b.... L3Q...Q.u..u..ee..l..a.a.b.b.. L4Q...Q.u..u.e..e.l.a.aa.bb.b. L5Q...Q.u..u.e..e.l.a..a.b..b. L6Q.Q.Q.u..u.eeee.l.a..a.b..b. L7Q..Q..u..u.e....l.a..a.b..b. L8.Q.Q..u..u.e..e.l.a.aa.bb.b. L9.QQ.Q..uu...ee..l..a.a.b.b..