Arduino persistens av Vision visar
Maskinvaruinstallation för en PoV display är ganska enkelt, men detta instructable innehåller kod där displayen kan kontrolleras och programmerade lätt över seriell anslutning, och inställningar kan sparas så att de automatiskt laddas och körs när ström från ett batteri.
Kommer du en Arduino AVR microcontroller ombord, som en Uno, Nano eller mini. Cirka 10 lysdioder och 10 motstånd från ca 100 till 220 ohm.
I vårt exempel kommer vi att anta en 10 LED-skärm. Wire LED i serie med ett motstånd till digital I/O stift 3-10, och ordna dem i en rak rad.
Ladda bifogade skissen.
Från den seriella monitor eller terminalemulator, skriv h för att få hjälp-menyn. Detta kommer att visa flera kommandon.
Min Serial reader klass komprimerar tomt utrymme, så du vill använda. att representera "off" i inställningarna för raden. Se bifogade Quelab.dat prov linjen inställningen indatafilen. I linje med denna fil kan klippa och klistras in i en terminalemulator ställa in PoV meddelandet.
När din önskad skärm har laddats, använda s) kommandot för att spara inställningarna till EEPROM som ska användas vid nästa reset.
int dummy = 0; Detta är att tvinga skiss att sätta arduino här
#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 {
korta nCols; Nej. kolumner i buffert
korta spaceCols; Nej. kolumnerna "space" tid innan repeat eller vända
kort läge; MODE_ kod från ovan
korta cylonCols; Nej. du sätter av tid för varje cylon blixt
int colTime; millisekunder/kolumn
int misc [3]. reserverat för framtida användning
kort disp [MAX_COLS]; Visa flaggor
} Staten.
Detta är DI/O stiften används för att Visa
#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);
för (int jag = 0; jag < n; i ++, bp ++) * bp = EEPROM.read(i);
om (! validState()) initState();
}
void saveState()
{
int n = sizeof(State);
byte * bp = (byte *)(&State);
för (int jag = 0; jag < n; i ++, bp ++) EEPROM.write(i,*bp);
}
Ange en rimlig standard
void initState()
{
State.nCols = 2;
State.spaceCols = 1;
State.cylonCols = 10;
State.mode = MODE_PoV;
State.colTime = 10; MS
för (int jag = 0; jag < MAX_COLS; i ++) State.disp[i] = (jag & 1)? 0x5555:0x2aaa;
saveState();
}
void setup()
{
int i;
för (jag = 0; jag {
pinMode(ledPins[i],OUTPUT);
}
pinMode(13,OUTPUT); använda ombord LED
återställa tillståndet från EEPROM
loadState();
Serial.BEGIN(9600);
}
void loop()
{
checkCommand();
int i, dt, k;
DT = State.colTime;
växel (State.mode)
{
fall MODE_CYLON:
DT * = State.cylonCols;
för (jag = 0; jag < NPINS; i ++)
{
digitalWrite(ledPins[i],HIGH);
Delay(DT);
digitalWrite(ledPins[(i+NPINS-1)%NPINS],LOW);
Delay(DT);
}
för (jag = NPINS-2; jag > = 0; i--)
{
digitalWrite(ledPins[i],HIGH);
Delay(DT);
digitalWrite(ledPins[(i+1)%NPINS],LOW);
Delay(DT);
}
bryta;
fall MODE_PoV:
för (jag = 0; jag < State.nCols; i ++)
{
kort mask = 1;
för (k = 0; k < NPINS; k ++, mask << = 1)
digitalWrite (ledPins [k], (mask & State.disp[i])? HIGH:LOW);
}
för (k = 0; k < NPINS; k ++) digitalWrite(ledPins[k],LOW);
Delay(State.spaceCols*DT);
bryta;
standard: / / random standard
{
DT * = 10;
k = random(100);
int lvl = (k < 50)? LÅG: HÖG;
int j = random(NPINS);
digitalWrite(ledPins[j],lvl);
Delay(DT);
}
}
digitalWrite(13,digitalRead(13)? LOW:HIGH); Toggle heartbeat
}
enkät för kommandon från serieporten
void checkCommand()
{
kort mask;
IF (!. LineBuf.isComplete()) avkastning.
char nyckel = lowCase(*(LineBuf.get()));
Switch(Key)
{
kort mask;
int k;
char * b;
fallet "h":
Serial.println ("h) hjälp (skriva detta meddelande)");
Serial.println (s) spara staten");
Serial.println ("r) random lights läge");
Serial.println ("c) cylon-läge");
Serial.println("p) PoV sign läge");
Serial.println ("n) ingen. cols att Visa");
Serial.println ("t) col tid, ms);
Serial.println ("b) tomma kolumner mellan upprepa");
Serial.println ("i) nytt initiera state");
Serial.Print ("Lx) ange mönster för rad x, 0 < = x < =");
Serial.println(NPINS);
bryta;
fallet ": saveState(); bryta;
fallet "r": State.mode = MODE_RANDOM; bryta;
"p" i mål: State.mode = MODE_PoV; bryta;
fallet "c": State.mode = MODE_CYLON; bryta;
fallet "i": initState(); bryta;
fallet "n": State.nCols = nextInt(LineBuf.get()+1); bryta;
't i mål ": State.colTime = nextInt(LineBuf.get()+1); bryta;
fallet "b": State.spaceCols=nextInt(LineBuf.get()+1); bryta;
fallet "l":
{
char * b = LineBuf.get () + 1.
int k = ((int)(*b)) - ((int) '0');
om ((k<0) || (k > 15)) bryta;
b ++;
kort mask = (kort) (1 < för (int i = 0; i < State.nCols; i ++, b ++)
{
om (isOn(*b)) State.disp[i] | = mask;
annat State.disp[i] & = ~ mask;
}
bryta;
}
standard:
Serial.Print okänt ("kommando: <");
Serial.Print(LineBuf.get());
Serial.println(">");
Serial.println ("Skicka kommandot h för hjälp.");
}
printState();
printMsg();
}
void printState()
{
Serial.Print(State.nCols);
Serial.Print ("kolumner");
Serial.Print(State.spaceCols);
Serial.Print("");
Serial.Print(State.colTime);
Serial.println("MS/Col");
Serial.flush();
}
void printMsg()
{
int i, k;
Serial.println();
för (jag = 0; jag < State.nCols; i ++) Serial.print("-");
kort mask = 1;
för (k = 0; k < NPINS; k ++, mask < = 1)
{
för (jag = 0; jag < State.nCols; i ++) Serial.print (State.disp [k] & mask?" X":" ");
Serial.println("|");
}
Serial.println();
för (jag = 0; jag < State.nCols; i ++) Serial.print("-");
Serial.println();
Serial.flush();
}
parse nästa int från en sträng
int nextInt (const char * s)
{
CONST char * c = s;
int val = 0;
for(;;)
{
int k = ((int)(*c)) - ((int) '0');
om ((k<0) || (k>9)) returnera val;
Val * = 10;
Val += k;
c ++;
}
}
bool isOn (const char c)
{
om ((c == '0') || (c=='.') || (c==' ') || (c==0)) returnera false;
om ((c == '1') || (lowCase(c)=='x')) return true;
return true;
}
bool validState()
{
Kontrollera för fåniga stat, angetts som standard om inkonsekvent
om ((State.mode < = 0) || (State.mode > 3) ||
(State.nCols < 1) || (State.nCols>MAX_COLS)) returnera false;
om ((State.spaceCols < 1) || (State.spaceCols > 10 * MAX_COLS)) returnera false;
om ((State.colTime < 1) || (State.colTime > 10000)) returnera false;
om ((State.cylonCols < 1) || (State.cylonCols > 10000)) returnera false;
return true;
}
---ioUtil.h
klass SerialLineBufferPrivates;
klass SerialLineBuffer
{
offentlig:
SerialLineBuffer();
~ SerialLineBuffer();
bool isComplete(); läsningar av seriell, returnerar sant om 0 eller EOLN
void förloppsindikatorförekomstens;
void begin();
int length() const;
int maxLength() const;
char * get(); Hämta aktuell buffert och rensa
char buf [SERIAL_BUF_LEN + 1];
skyddad:
int _maxLength, _len;
bool _complete;
privat:
Undergrupp 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 * nyckel, const char * Nyckel1);
---ioUtil.cpp
#include
#define NULL-0
vill inte att bero på ctype.h, bara för detta!
bool isBlank (int c)
{
IF(c == 7) return(false); Bell
tillbaka ((c < = "") || (c > '~') );
}
#if defined(ARDUINO) & & ARDUINO > = 100
#include
#warning ARDUINO
#else
#error ARDUINO inte > = 100
#include
#endif
void SerialLineBuffer::begin()
{
_maxLength = SERIAL_BUF_LEN; AVR dynamiska mem är knepigt
_len = 0;
_complete = false;
}
SerialLineBuffer::SerialLineBuffer() {begin();}
bool isTerminator (int c)
{
om (c == 0) return(true);
om (c == ';') return(true); sändande \n till följetong är knepigt. acceptera detta alltför.
om ((c == "\n") || (c=='\r') || (c=='\m')) Return(true);
om ((c > = 10) & & (c < = 13)) return(true); \r, \n, form feed, vert fliken
Return(false);
}
läsa från seriell, återvändande sant om 0 eller EOLN
bool SerialLineBuffer::isComplete()
{
om (_complete)
Return(true); inte Läs mer tills raden är konsumeras
lägga till tecken från serial
While(Serial.available() > 0)
{
int nextByte = Serial.read();
Serial.Print ("fick"); Serial.println(nextByte);
om ((nextByte < 0) || (nextByte > = 256))
Return(_complete);
om (isTerminator(nextByte))
{
Serial.Print ("terminator"); Serial.println(nextByte);
BUF [_len] = 0;
_complete = (_len > 0);
Return(_complete);
}
om (isBlank(nextByte))
{
Serial.Print ("tomt"); Serial.println(nextByte);
om (_len > 0) / / ignore ledande blanktecken
{
om (buf [_len-1]! = "") / / compact utrymme till 1 utrymme
{
BUF [_len ++] = ""; konvertera alla utrymme att ""
}
}
}
annat
{
BUF [_len ++] = (char) nextByte;
}
Låt inte spill
om (_len > = _maxLength)
{
Serial.println ("\nOverflow. «««trunkeras kommandosträngen");
_complete = sant;
}
}
Return(_complete);
}
void SerialLineBuffer::clear()
{
_len = 0;
_complete = false;
}
int SerialLineBuffer::length() const {return(_len);}
int SerialLineBuffer::maxLength() const {return(_maxLength);}
Hämta aktuell buffert och rensa
char * SerialLineBuffer::get()
{
BUF [_len] = 0;
förloppsindikatorförekomstens;
Return(BUF);
}
//-----------------------------------------------------------
Dela en sökord-värde par sträng i en sträng med nyckel och Värdesträngen
CONST char nullChar = 0; statisk är skrämmande på AVR
char * extractKey (char * cmdStr, char ** val)
{
* val = (char *) & nullChar;
om (cmdStr == NULL) return(NULL);
char * nyckel = cmdStr;
medan (* nyckel) / / bearbeta kommentarer
{
om (* nyckel == "#") * nyckel = 0; Kommentar
annan nyckel ++;
}
nyckel = cmdStr;
medan (* nyckel & & isBlank(*key)) nyckel ++; trimma blanksteg
* val = nyckel;
medan (** val & &! isBlank(**val)) * val + = 1; hoppa över nyckel
** val = 0;
* val + = 1;
medan (** val & & isBlank(**val)) * val + = 1; hoppa över blanktecken
Return(Key);
}
char lowCase(const char a)
{
om ((en > = "A") & & (en < = "Z"))
{
int sft = ((int) "a")-((int) 'A');
int b = (int) en + sft;
Return((Char)b);
}
Return(a);
}
int caseCmp (const char a0, const char b0)
{
char en = lowCase(a0);
char b = lowCase(b0);
om (en < b) return(-1);
återgå ((a>b)? 1:0);
}
bool keyMatch (const char * key0, const char * Nyckel1)
{
Serial.Print("keyMatch("); Serial.Print(key0); Serial.Print(","); Serial.Print(key1); Serial.Print(")=");
medan (* key0 || * Nyckel1)
{
om (caseCmp (* key0, * Nyckel1))
{
Serial.println("false");
Return(false);
}
om (* key0) key0 ++;
om (* Nyckel1) Nyckel1 ++;
}
Serial.println("true");
Return(true);
}
---Indata exempel
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..