Вы находитесь на странице: 1из 22

4/4/2015

Arduino

Arduino
Preface
Arduinoisanawesomewaytogetintorobotics.ItisaveryeasytousemicrocontrollerthatyouprograminC/C++.Itdoesanalogdigitalon/offinputand
output,readingofvoltages,anologoutputbyPulseWidthModulation(PWM)whichisusefulforhookingupmotors,serialcommunicationwhichisuseful
forcommunicatingwithsensorsandotherexternaldevices.
AsimpleArduinoprogramexampleisblinkinganLED.Thecodelookslikethis:
intled=13;//Pin13hasanLEDconnectedonmostArduinoboards.
voidsetup(){//thesetuproutinerunsoncewhenyoupressreset:
pinMode(led,OUTPUT);//initializethedigitalpinasanoutput.
}
voidloop(){//thelooproutinerunsoverandoveragainforever:
digitalWrite(led,HIGH);//turntheLEDon(HIGHisthevoltagelevel)
delay(1000);//waitforasecond
digitalWrite(led,LOW);//turntheLEDoffbymakingthevoltageLOW
delay(1000);//waitforasecond
}

Nottoohard,right?WehavelotsoftutorialsonhowtodomoreadvancedthingswithyourArduino.

PulseWidthModulationwithanalogWrite
PulseWidthModulation(PWM)isusedbecauseamicrocontrollercannoteasilysendaspecificvoltages.Itreallycanonlyturnaswitchonandoff.Tobe
abletosendaratioofthecurrentvoltage,somethinglikeavariableresistorwouldneedtobedigitallycontrolled,butwedon'thavethat.Instead,what
PWMdoesisessentiallyfliptheswitchreallyreallyfast.Thatwaytheaveragevoltagecanbevariedbyleavingtheswitchonforlongerorshorterthanit
isoff.

So,theaveragevoltageisthepercentdutycycle,multipliedbythe"on"voltage.

ArduinoExample
Toget2.5averagevolts,justusea50%dutycycle,sincetheArduinooutputs5Vnormally.
However,thePWMfunctioninarduinodoesnottakedutycycleasapercentage.Ittakesitasawholenumberoutof255.So,a100%dutycyclewouldbe
255.The50%dutycyclewouldbe0.50*255=127.
BesuretouseapinontheArduinothathasa~nexttoit,whichrepresentsthatthepincandoPWM.Notallpinscan.OnanArduinoUno,theavailable
pinsare3,5,6,9,10,and11.Inthisexample,wewilluse5fornoparticularreason.
Theresultingcodetooutput2.5averagevoltswilllooklikethis:
analogWrite(5,127);//pin5,halfof255for50%

ReadingNumbersFromSerial
Introduction
ReadingnumbersfromserialonanArduinoisneededsurprisinglycommonly.Exactlywhatishappeningmightbekindofhardtofigureout.
Serial
Serialcommunicationisdigital,whichmeansalldataistransmittedin1'sand0's.Typically,serialcommunicationisdoneusingASCIIletters.Thismeans
that,tosendanumbertotheArduino,thedatasentisnotthebinaryversionofthenumberinbase2(asaninteger),butinsteadasequenceofcharactersfor
eachdigitinbase10(whichishumanreadable).Itisnotanefficientuseofbandwidth,butbandwidthisnotusuallyaproblemwithArduinosconnectby
USB.

http://roboticcontrols.com/book/export/html/10

1/22

4/4/2015

Arduino

ArduinoCode
charcommandLetter;//thedelineator/commandchooser
charnumStr[4];//thenumbercharactersandnull
longspeed;//thenumberstoredasalonginteger
voidserialEvent(){
//Parsethestringinputonceenoughcharactersareavailable
if(Serial.available()>=4){
commandLetter=Serial.read();

//dumpthebufferifthefirstcharacterwasnotaletter
if(!isalpha(commandLetter){
//dumpuntilaletterisfoundornothingremains
while((!isalpha(Serial.peak())&&Serial.available()){
Serial.read();//throwouttheletter
}

//notenoughlettersleft,quit
if(Serial.available()<3){
return;
}
}

//readthecharactersfromthebufferintoacharacterarray
for(inti=0;i<3;++i){
numStr[i]=Serial.read();
}

//terminatethestringwithanullpreventsatolreadingtoofar
numStr[i]='\0';

//readcharacterarrayuntilnonnumber,converttolongint
speed=atol(numStr);
Serial.println(speed);
}
}

CodeExplanation
serialEvent
serialEventisafunctionthatiscalledbyArduinobeforeeachloop.So,youcanseparateoutyourserialhandlingfromtherestofyourcode.Youcouldalso
putthecontentsofthisfunctionintheloop()functionanditwouldbesimilar.
FixedWidth
Commandsneedtobedelineatedinsomeway.FixedwidthcommandsareconvenientonArduinobecausetheSerial.availablefunctiontellsyouhowmany
charactersarewaiting.Itisalsopossibletodelineatebyspecialcharacters.AnextremelycommonandsimpleversionofthisisaCommaSeparatedValue
file.However,sinceitissimplesttouseCstrings,thecharacterarrayswhichtheserialisreadintoisnecessarilyfixedwidthanyway.Togetaroundthis
issue,avectororlinkedlistcouldbeused,sotheserialstringcandynamicallygrowandshrink.
CommandDifferentiation
Inmanycases,arobottakesmultiplekindsofinputs.Forexample,theremightbemultiplespeeds,oradirection,orsomekindoftrigger.Prefixingeach
commandwithauniquelettercanmakeiteasytodifferentiatewhatthefollowingstringissupposedtodo.
CStrings
Cstringsarearraysofchardatatypes.TheymustbeterminatedbyaNULLcharacter'\textbackslash0'.WithouttheNULLcharacterattheend,thereisno
wayforanyfunctiontoknowhowlongthestringis.Forexample,aprintfunctionwouldprintthestringandthenabunchofgarbagecharactersuntilitgets
toaNULLortheendofthememoryavailable.Inthiscase,it'slesslikelyforthattohappensinceweareonlyusingatol,whichwillonlyreaduntilthereis
anonnumericcharacter.AnonnumericbyteismorelikelytorandomlybeattheendofthestringthanaNULLcharacter.
ASCIITable

ChartoInteger
Convertingasinglecharactertoanumbertakesadvantageofhowcharactersarestored,whichistypicallyinaformatcalledASCII.
ThinkofacharofASCIIlikeanintegerdatatype.Exceptthatwhenprinted,itisnotadecimalnumber.Thenumberintheintis
translatedintoaletteronthescreenaccordingtoatable.Forexample,thedecimalnumber97istranslatedintotheletter'a'.Each
letterisreallystoredasa'number'.I'mshowingitasadecimal(base10)number,butitisreallystoredinbinary(base2).TheC++
compiletakescareoftranslatingourbase10decimalnumbersintobase2binary.
Hereishowtotakeadvantageofthis:
intnumber=(int)charInput(int)48;
//or:
intnumber=charInput'0';

Decimal Character
48

'0'

49

'1'

50

'2'

51

'3'

52

'4'

53

'5'

54

'6'

SinceASCIIstorestheletterssequentially,startingat0,justsubtractthevaluewhere0beginsfromeachofthecharactersto
convertittoitsnumericform.Thisworksregardlessofthebaseofthecharacterstorage.So,itconvertstheASCIIcharacter
representingthenumberinbase10intoanintegerinbase2.

55

'7'

56

'8'

CharArray(Cstring)toLongInteger

57

'9'

Now,eachofthelettersfromrighttoleftneedtobemultipliedbyapowerof10.Hereisthebasicideaofwhatatoldoes:
charcharArray[5]="5432";//doublequotesaddsthe\0attheend

http://roboticcontrols.com/book/export/html/10

2/22

4/4/2015

Arduino

longlongnum=0;//theconvertednumber
longexp=1;//startwith10^0
intindex=0;//thecurrentplaceinthearray
//findtheendofthestringwhencharacterisnotanumber
while(isdigit(charArray[idx])){
++idx;
}
//beginbasemultiplicationandnumberconversion
while(idx>=0){
//convertdigitcharactertoalong
longcurrentDigit=(long)charArray[idx](long)48

currentDigit*=exponent;//numbermultipliedby10^(lenidx)
exponent*=10;//nextnumbertoleftisanotherpoweroften

longnum+=currentDigit;

idx;
}

SerialCommands
Introduction
SerialcommunicationthroughUSBcanbeusedtocommunicatebetweenahostcomputer(likealaptop,orRaspberryPi),andanArduino.Doingso
allows:
Useofthefasterhardwareofthehostcomputerforcalculations
SynchronizationofmultipleArduinos
Useofotherinformationprovidedbythehostcomputer,likeinternetconnectionsorlargerdatafiles
Creationofagraphicalinterfaceusingthehost'sdisplayorwebserver

Communication
Communicationiseasy.ArduinoandPythonhavesimplemethodsforestablishingserialcommunication.
Arduino
voidsetup(){
Serial.begin(9600);//Initializeserialcommunicationat9600baud
}
voidloop(){
Serial.println('hello');
}

Python
fromserialimport*
ser=Serial("/dev/ttyACM0",9600)
while1:
printser.readline()

IncompleteMessages
Oneofthemostdifficultissueswiththissortofserialcommunicationisensuringthatcommandsarereceivedinentirety.Ifyousend"1000"fromPython,
andwantArduinotoreaditasshownbelow,Arduinomightread"10"andtheninanotherloop()rightafterwardread"00".
charincoming[11]="";
inti=0;
while(Serial.available()>0){
//readtheincomingbyte:
char[i]=Serial.read();
i++;
}
//Converttheincomingstringintoaninteger!
intnewNumber=atoi(incoming);

FixedLengthPackets
Onewaytosolvethisinanefficientmanneristouseafixedlengthforcommandsandwaituntilthereareenoughbyteswaitinginthebuffer.The
downsideisthatnocommandsmaybeissuedwithalengthlongerthanthefixedlength,andrequiresremaininglengthbewasted.
Python
ser.write('%10d'%1000)#padthenumbersoitis10characterslong

Nowjustaddaconditionsothatnoreadingisdoneunlessafullcommandiswaitingintheserialbuffer.
Arduino
http://roboticcontrols.com/book/export/html/10

3/22

4/4/2015

Arduino

if(Serial.available()>=10){
charincoming[11]="";
inti=0;
while(Serial.available()>0){
//readtheincomingbyte:
char[i]=Serial.read();
i++;
}
//Converttheincomingstringintoaninteger!
newNumber=atoi(incoming);
}

Delineation
Anotherwaytosolvethisproblemistodelineatecommandsbyplacingaspecialcharacterattheendofeachcommandtosignifythatthecommandis
complete.Theproblemwiththiswayisthatthelengthoftheincomingstringisunknown,andalongorimproperlyformedcommandcouldoverflowa
fixedlengtharray.Toovercomethislimitation,adynamicclassisusuallyused.TheStringobjectisagoodsolutionasitcanbeeasilyconvertedbackinto
acharacterarray.MaintainingdatatypeswithC++stringscanquicklybecomeconfusing,anditisextremelyimportantthatthedelineationcharacteris
neverusedinthecommand.TherearesomespecialcommandcharactersinASCIIthatwouldbegoodchoices.

MultipleCommandTypes
Youcansenddifferentcommandsoverthesamecommunicationlinebyattachingaprefixtothecommand.Forexample,speedandpositioncouldbesent
as"p000001000"and"s000000200"totelltheArduinotogotoposition1000ataspeedof200.
Python
ser.write('p%9d'%1000)#sendposition,paddedto9(plus1commandchar)
ser.write('s%9d'%200)#sendspeed,paddedto9(plus1commandchar)

Arduino
intposition,speed;
if(Serial.available()>=10){
//readthefirstcharacterasthecommand
charcommand=Serial.read();

charincoming[10]="";
inti=0;
//readtheincomingbyte:
char[i]=Serial.read();
i++;
}
//Converttheincomingstringintoaninteger,basedoncommand
if(command=='p'){
position=atoi(incoming);
}
elseif(command=='s'){
speed=atoi(incoming);
}
else{
//Thecommandwasnotoneoftherecognizedcharacters
Serial.println("COMMANDERRORNotrecognized");
}
}

Nowthatyourcommunicationisestablished,itisuptoyoutofigureoutwhattodowiththedataoneitherend.

SplittingaString
Introduction
Therearetimeswhenastringisrecieved,butratherthantheentirestring,justapieceofthestringisdesired.Unfortunately,theredoesnotappeartobea
simplewaytohandlestringsinC++.Therefore,Ihavedevisedawaytosplitastringbasedoncommaseparation.
Thiswayofsplittingstringsisrathercrudeandrefinementforitwillbeworkedon,butforimmediateuse,thecurrentfunctionisgivenwithtwoexamples
ofhowitcanbealteredandused.

Coding
SplittingStringsTwoCharacters
Thiscodewasusedinaprojectthatcontrolledarobotviacomputer.ThecomputersentdatathroughanXBeetoanArduinothatservedasthebrains.That
Arduinowouldgetthestringfromthecomputer,pickitapartandfindtheimportantinformation.ThatinformationwasthenrelayedtoanArduinothat
controlledtherobot'smotors.ThesinglecharacterthatwassenttothemotorArduinothentoldwhichdirectiontomovetherobotin.
//BrainCode
charstring[25];
charid[2];
chardirect[2];
intii=0;

http://roboticcontrols.com/book/export/html/10

4/22

4/4/2015

Arduino

voidsetup(){
Serial.begin(9600);//setupSeriallibraryat9600bps
Serial1.begin(9600);
//Serial.println("Motortest!");
}
voidloop(){
}
voidserialEvent(){
inti=0;
if(Serial.available()){
delay(50);
while(Serial.available()){
string[i++]=Serial.read();
}
string[i++]='\0';
splitString(string);
if(id[0]=='M'){
Serial1.print(direct[0]);
}
}
}
voidsplitString(char*chars){
charval1[15]={};
charval2[15]={};

inti=0;
intcnt_id,cnt_val1,cnt_val2;
//getidentifier
while(chars[i]!=','&&i<25){
i++;
if(chars[i]==','||chars[i]=='\0'){
for(intj=0;j<i;j++){
id[j]=chars[j];
cnt_id=j;
}
id[cnt_id+1]='\0';
//Serial.println(id);
}
}
i++;//skipsthecomma

while(chars[i]!='\0'&&i<25){
i++;
if(chars[i]==','||chars[i]=='\0'){
for(intj=cnt_id+2;j<i;j++){
direct[j(cnt_id+2)]=chars[j];
cnt_val1=j2;
}
direct[cnt_val1+1]='\0';
//Serial.println(direct);
}
}
}

Aquestionmayariseofwhyevenbotherwiththiscode?Whynotdirectlysendtothemotorswhichdirectiontomove?Andinthiscase,yes,thatwould
havebeenmuchsimpler.However,thisisonepartofamuchbiggerprojectwheremorethanjustmotorinformationwillbesent,sothefirstcharacter
beingsentinwillindicatewhichpartoftherobotitpertainsto.
SplittingStringsGettingFloats
Oftentimes,itmaybenecessarytosendactualnumbervalues,whetherthatisafloatoraninteger,throughserial.Therefore,thereneedstobeawayto
recoverthatdata.Itcanbesentasabyte,butfloatsandlargerintegersmaynotfitintoabyte.
Forexample,inaprojectitwasnecessarytosendastringlike"L,1234.5678,2345.6789"throughserialtoanArduino.Thisisinteprettedassendinga
LocationtotheArduinowiththefollowingcoordinates.Thiswouldinvolvebothsplittingupthestringandturningthenumbervaluesintofloats.
Unfortunately,therearenotveryelegantwaystohandlestringsinC,sotwofunctionshadtobemadebyscratchtosplitthestring.Inthisparticular
example,thiswastheonlytypeofstringthatwasgoingtobesenttotheArduino,socodewasmadetosplitthisspecificstring,butitcanbeadaptedto
othermeans.
Thefollowingcodeshowshowthestringissplit:
voidsplitString(char*chars,char*id,double&numX,double&numY){
charval1[15]={};
charval2[15]={};

inti=0;
intcnt_id,cnt_val1,cnt_val2;
//getidentifier
while(chars[i]!=','&&i<25){
i++;
if(chars[i]==','||chars[i]=='\0'){
for(intj=0;j<i;j++){
id[j]=chars[j];
cnt_id=j;
}
id[cnt_id+1]='\0';
}
}

http://roboticcontrols.com/book/export/html/10

5/22

4/4/2015

Arduino

i++;//skipsthecomma

//getfirstfloat
while(chars[i]!=','&&i<25){
i++;
if(chars[i]==','||chars[i]=='\0'){
for(intj=cnt_id+2;j<i;j++){
val1[j(cnt_id+2)]=chars[j];
cnt_val1=j2;
}
val1[cnt_val1+1]='\0';
CharToFloat(val1,numX,cnt_val1+1);
}
}
i++;//skipsthecomma
//getsecondfloat
while(chars[i]!='\0'&&i<25){
i++;
if(chars[i]==','||chars[i]=='\0'){
Serial.println(chars[i]);
for(intj=cnt_id+cnt_val1+4;j<i;j++){
val2[j(cnt_id+cnt_val1+4)]=chars[j];
cnt_val2=j;
}
val2[cnt_val2+1]='\0';
CharToFloat(val2,numY,cnt_val2+1);
}
}
}

Itmaybenoticedthatinthiscase,afunctionCharToFloatiscalled.Thisfunctionisexplainedinanothertutorial.Itisonemethodforturningcharacter
arraysintomoreprecisefloats.

CharacterArraytoFloat
Introduction
Sometimesitisnecessarytoturncharacterarraysintofloats.However,precisioncanbeanissuewhenusingsomeofthecurrentfunctions.Thefollowing
functionturnscharacterarraysintoafloatthatissplitfromthefronthalfandthebackhalf.Thisisonemethodforamoreprecisefloat.

Coding
ThefollowingcodeshowstheCharToFloatfunctionthatturnsthesplitCharacterArrayintoafloat.Itshouldbenotedthatthefunctionsplitsthefloatinto
aforwardhalfandabackhalf.ThisisduetotheArduino'scapabilities.Floatscanonlyeverhave7digits,whichmeansifyouneedanymorethanthat,the
accuracyofthefloatdecreases.Itwillremember7ofthenumbersandthenmakethebestguessitcanfortherest.Thiscanbeaproblemifprecisioniskey.
And,no,usingdoublewillnotfixtheproblem.IntheArduino,floatanddoublearethesamething.Therefore,splittingthefloatintotwosectionscanretain
theaccuracywithsomeinconvenience.
voidCharToFloat(char*chars,double*value,intcount){
inti=0,l=0;
floatmultiplier;
floatfront=0.0,behind=0.0;
value=0.0;

//beforedemicalpoint
while(chars[i]!='.'&&i<count){
i++;
if(chars[i]=='.'){
intq=i;
for(intj=i;j>0;j){
multiplier=1;
for(intk=q;k>1;k){
multiplier*=10;
}
front+=(chars[l]'0')*multiplier;
l++;
q;
}
l++;
}
}

intn=i;
//afterdemicalpoint
while(chars[n]!='\0'&&i<count){
n++;
if(chars[n]=='\0'){
intq=n,l=n1;
for(intj=n1;j>i;j){
multiplier=1;
for(intk=q(i+2);k>=0;k){
multiplier=0.1*multiplier;

http://roboticcontrols.com/book/export/html/10

6/22

4/4/2015

Arduino

behind+=(chars[l]'0')*multiplier;
l;
q;
}
}
}
value[0]=front;
value[1]=behind;
}

Thismaynotbethemostelegantwaytoturnacharacterarrayintoafloat,butitworks.Needlesstosay,thisdoesnotappeartobecommonpractice,but
seemslikeitmightbeacommonproblem.

ArduinotoArduinoSerialCommunication
Introduction
ItispossibletochainArduinostogetherinsuchawayastogetcommunicationbetweenthetwo.HavingArduinoArduinocommunicationcanbeuseful
formanyprojects,suchashavingoneArduinotorunmotorsandhavinganothersensethesurroundingsandthenrelaycommandstotheotherArduino.
Thiscanbedoneinseveralmethods,usingI2CandSerial,tolistafew.
ThistutorialwillfocusonArduinoArduinocommunicationthroughtheserialports(RXandTX).

Schematic
TheschematicbelowshowshowtoconnectthetwoArduinostogether.ThisshowstwoUnos,butifaMegaisused,itcanbeconnectedtoanyoftheSerial
portsontheMegaaslongasthatisaccountedforinthecode.

Therehastobeacommongroundbetweenthetwoorelseitwillnotfunctionproperly.Also,notethatTXgoestoRXandRXgoestoTX.

Coding
Whensendingthingsthroughserial,everythingissentinbytes.ThesebytesarethenreadonebyteatatimebytheotherArduino.Whenitisjustcharacters
beingsentthroughtheserial,itisrelativelyeasytoconvertfromcharacterstobytes.However,iftherearebothcharactersandnumbersaregoingthrough,
thiscanleadtomessingupthedatabecauseanumberandacharactercanhavethesamebytevalue,butthatdoesnotmakethemthesame.Numbersare
alsotrickybecausetheymaynotactuallyfitinthebyte.
SimpleCode
Theeasiestwaytogetaroundthisistotrytoavoidusingcharactersandnumbersatthesametime.Thiscanbedonebysendingonecharacteracross,each
withadifferentmeaning.AgoodexampleofthiscomesfromtheArduinoPhysicalPixeltutorial.
UploadthePhysicalPixelcode,whichcanbefoundintheArduinoIDEunder:File>>Examples>>Communication,ontooneArduino.
OntheotherArduino,upload:
voidsetup(){
Serial.begin(9600);
}
voidloop(){
Serial.print('H');
delay(1000);
Serial.print('L');
delay(1000);
}

Whenthisisrun,theLEDattachedtoPin13ontheArduinowiththePhysicalPixelcodeshouldflashonandoffatafrequencyof0.5Hz.Tomakesure
thisisactuallythecodedoingthat,thedelayscanalwaysbechangedintheabovecode.
Inthiscodethejobof'H'wastoturnanLEDonandthejobof'L'wastoturntheLEDoff.Thiscaneasilybeapplicabletogettingvariouscharacters
triggeringmorereactions.
However,dependingontheapplication,thismaynotbeenoughandmoredrasticcodemayberequired.
ComplexCode
ForsendingdatafromoneArduinotoanotherinaformthatcannotbesimplified,thereareotheroptions.Oneoptionistoturneverythingsentfromthe
http://roboticcontrols.com/book/export/html/10

7/22

4/4/2015

Arduino

SenderArduinointocharactersandthenhavetheReceiverArduinoreadinthecharacters.Thedataisactuallysentasbytes,buttheArduinocanconvert
fromcharacterstobytesandviceversa.
SenderCode
Thesendercodechangescharactersintobytesand,ifnecessary,itchangesnumbervaluesintocharactersbeforeturningitintobytes.Belowisasampleof
theSendercode:
//SenderCode
charstr[4];
voidsetup(){
Serial.begin(9600);
}
voidloop(){
intvalue=1234;//thiswouldbemuchmoreexcitingifitwasasensorvalue

itoa(value,str,10);//Turnvalueintoacharacterarray
Serial.write(str,4);
}

ReceiverCode
ThereceiverwillthenreceivethebytearrayfromtheotherArduinoandinterpretitthere.Belowisthecodeforthereceiver.Notethatthiscodeisintended
foraMegasinceitwillinterpretthedatareceivedfromtheotherArduinoandthenprinttotheSerialMonitorwhatitreceivedsothattheusercancheckit.
ThisdebuggingcanbeavoidedbyusinganUnoandthenprintingwhatwasfoundontoanLCDscreenthatusesI2Ccommunication.
//ReceiverCode
charstr[4];
voidsetup(){
Serial.begin(9600);
Serial1.begin(9600);
}
voidloop(){
inti=0;
if(Serial1.available()){
delay(100);//allowsallserialsenttobereceivedtogether
while(Serial1.available()&&i<4){
str[i++]=Serial1.read();
}
str[i++]='\0';
}
if(i>0){
Serial.println(str,4);
}
}

Thereisoneflawwiththisprogramasitisnow.Itresultsinonlyacharacterarray,soiftheintegersweredesired,theyarelostwithoutfurtherworkonthe
data.
Furthertutorialshavebeenmadetoshowhowthisdatamaybemanipulatedbysplittingstringsorgettingfloatsfromthecharacterarrays.

OptimizedMultiplePinReads
MemoryAddressing
First,tounderstandwhythingsaredonethisway,itshouldbeknownthatabool(booleantrue/false)isonly1bit.1fortrue,0forfalse.However,
computershaveanaddressingsystemformemory,whichcannotgodirectlytoasinglebit.Anaddressusuallygoestoa8bitchunkofmemory(abyte),
whichisalsousuallythesamesizeasanintdatatype.
Thinkofitliketryingtowriteapostaladdresstoaroominahouse.Theaddresswilltakeyoutothehouse,butnotinside.So,wecan'tjustkeepitinits
ownvariable.
Furthermore,itwouldbewastefultowaste7bitsforeverybooldeclared.8boolscanbeputallintooneintegerallnexttoeachotherinmemorytosave
space.Howdoyouseperatethem?Howdoyougetjustonebitoutofachunkofbits?Withbooleanlogic!

PortManipulation
Tobeasefficient,Arduinogroupspinstogetherinto8bit"int"variables.Usingbooleanlogic,youcanperformoperationsonpinsyourself,insteadof
usingthebuiltinfunctions.ThisiscalledPortManipulation.Thereare3groupsof3variables.First,thepinsarebrokenupintogroupsof8basedon
number.
D:Arduinodigitalpins0to7
B:Arduinodigitalpins8to13
C:Arduinoanalogpins0to5
Then,thereare3typesofregisterswhichcanperformdifferentactions,eachwithathecorrespondingletterreplacingthe'#':
DDR#:DataDirectionRegister.
http://roboticcontrols.com/book/export/html/10

8/22

4/4/2015

Arduino

Setswhethertheeachpinisreadfromorwrittento.
PORT#:PortI/O
Canwritetoeachpinahighorlowstate,butcanalsoberead
PIN#:PinInput
Canreadthecurrentpinstatesofthepinsininputmode.

Readingthepins
Pinsareoranizedintheregisterfromlowestnumberattheright,tohighestnumberattheleftInthisexample,pins11through13aresetasINPUT.Pins11
and13arecurrentlyhighatthemoment,butpin12islow.
Pin:

NA NA Pin13 Pin12 Pin11 Pin10 Pin9 Pin8

DecimalValue 128 64

32

16

PINB

SelectP13

SelectP11

Asyoucansee,ifyouweretoprintthevalueofPINCwithpins13and11highbut12low,thevaluewith32+8=40.
ToselectasinglepinoutofthePINCregister,bitwiseANDitwithanintinthesameplaceasthepin.So,PINB&SelectP13=13,or0B00100000.
ConditionsinC++willbetrueforanynonzerovalue.IfPin13werelow,thentheresultwouldhavebeen0,or0B00000000.

ProgrammingExample
First,youhavetosetwhetherthepinsareinreadorwritemode.Sincethisisoftendoneexclusivelyinsetupandonlyonceperprogram,itisnotas
importanttooptimizethis.ItmaybeeasiesttojustusepinMode()tosetthestatesinsteadofthemoreadvancedwaysdescribedbelowwiththeDDR#
register.
voidsetup(){
pinMode(11,INPUT);
pinMode(12,INPUT);
pinMode(13,INPUT);
}
voidloop(){
//ThisconditionisasingleCPUoperation
//pins11,12,and13areallinthePINBgroupattheleft
if(PINB&0B11100000){
Serial.println("Pin11,12,or13werehigh");
}

//thisconditionrequiresdozensofoperations
if(digitalRead(11)||digitalRead(12)||digitalRead(13)){
Serial.println("Pin11,12,or13werehigh");
}

Intheaboveexample,theslowersecondmethodeachdigitalReadmustfirstfigureoutwhichregisterthepinisin,selectitwithabitwiseand,andreturnit
tothecondition.Then,eachpinstatemustbeORdtogether.
Obviously,thiscaseisnotatypicalone,butthereareotheruses.Forexample,onecouldwritetoseveralpinsatonce.Thisoptimalmethodbecomes
extremelyimportantwhenspeedisanissue.Whenreadingpinseveryfewmicrosecondsoninterrupts,itcanbebeneficialtofirststorethewholeregister
intoabuffer,thendotherequiredcomparisonslaterinordertoinsurethatallchangesarebeingcaptured.Otherwise,datacouldbelostiftheinterrupt
functionisinterruptedbeforeitcancomplete.

BuildArduinoSketchesfromCLIwithMake
Reasons
TheArduinoIDEhasalotofnicefeatures.It'ssoeasy,it'sreallyoneofthemainreasonswhyyouwouldchoosetobuyanArduinooverotheroptions.It
canbeannoyingsometimesthough.IfyouwanttodistanceyourselffromtheIDE,butstillliketheArduinoplaform,it'sreallyaseasyasjustmakinga
reallysimpletextfileandrunning"make".
Bygettingacommandlineinterface,youcanalsoautomatethebuildanduploadprocess.Youcandetectports,oruploadtomultipleArduinosatonce.

Installation
Ubuntucommand:
sudoaptgetinstallavrdudemakegccavrarduinomk

Usage
Createatextfilecalled"Makefile"inthesamefolderasyourproject
ARDUINO_DIR=/usr/share/arduino
TARGET=projectName#Thesameasyourinofilename
BOARD_TAG=uno#canalsobemega2560

http://roboticcontrols.com/book/export/html/10

9/22

4/4/2015

Arduino

ARDUINO_PORT=/dev/ttyACM0#besuretochangethistotheportusedbyyourboard
#CanaddArduinolibraries.Example:
#ARDUINO_LIBS=EEPROM
ARDUINO_DIR=/usr/share/arduino
AVR_TOOLS_PATH=/usr/bin
include/usr/share/arduino/Arduino.mk

Onceyouhavethatfile,allyouneedtodoisjustsay:
makeupload

Ifyouaren'tusinganArduinoUno,youcancheckwhichboardsareavailablewith:
makeshow_boards

AdvancedUsage
ItmightbehelpfultojustautodetectalloftheArduinosconnectedanduploadthesameimagetoallofthem.Hereisanicesimplewaytodothatwith
bash:
Makefile:
ARDUINO_DIR=/usr/share/arduino
TARGET=tempTargetName
BOARD_TAG=uno
ARDUINO_PORT=${arduino}
ARDUINO_DIR=/usr/share/arduino
AVR_TOOLS_PATH=/usr/bin
include/usr/share/arduino/Arduino.mk

Thenmakeabashfile.Thiswillbeexecutedinsteadofthemakecommand.
make.sh:
#!/bin/bash
#lookforanyArduinos.
#Thecurrentoneswereconnectedrecentlyandwithinthesameminute
forain`lslt/dev/ttyACM*|awk'BEGIN{first=1}{if(first){current=$9;first=0}if($9==current){print$10}else{exit}}'`
do
echo"uploadingto$a"
makearduino=$aupload
if[$?ne0];then
echo"nonzeroreturnstatus"
exit
fi
done

Now,allyouneedtodotocompileanduploadtoallrecentlyconnectedarduinosisrun:
bashmake.sh

KernelEventdrivenDelaysandIntervals
ReasonstouseKernel
delay()isBad
WhenyouusedelayordelayMicrosecondsinArduino,nothingelsecanhappenuntilthedelayisfinished,whichcanbeahugeproblemifyouhavemore
thanonethinggoingonsimulteneously,aswillalwaysbethecasewhenbuildingamoreadvancedrobot.
Imaginethatyouwanttocheckasensoronceasecond.Easyenough.Justdelaythencheckthesensor.WhatifyouwanttoblinkanLEDonandoffevery
40ms,butstillcheckingthatsensor.Anydelaysusedbyonewillmessupthetimingontheother.Ifyoudelayonesecondaftercheckingthesensor,the
lightwillnotblinkduringthattime.Youcouldmakeafixednumberofblinksbetweensensorchecks,butthatisinflexibleandaccumulateserror.
ProblemswithAlternatives
Twoalternativesalreadyexist.Botharebasedontheideaofconstantlyasking"canIgoyet?"inanifstatement.
Youcancheckthetimesyourself,butthatrequiresalotofworkandcanmakethecodehardtoread.
YoucanalsouseMetro,whichwrapsthecheckupintoaniceclasswhereyoujustsetanintervalandruna.check()method.
IreallylikeMetro,butitstillrequirestheprogramtobewrittensomewhatlinearlyinsteadofinseperatefunctions,anditisnotreallymeanttobeusedfor
onetimedelays.
IfyouareusinganArduinoDue,theretheSchedulerlibrarythatprovidesaneasierinterface,butisexclusivetotheDue'sARMCPU.
http://roboticcontrols.com/book/export/html/10

10/22

4/4/2015

Arduino

EventsareEasyandPowerful
Ifyou'veeverdealtwithGUIsorJavascript,you'reprobablycomfortablewithevents.They'reanicewaytomakethemostuseoutofasinglethreaded
application(likeabrowserwindow,oranArduino)because,aslongasyouavoidanyblocking,thingshappenwhenthey'resupposedto.
Essentially,each"task"isafunctionwhichgetscalledonlywhenthe"event"happens.Theevent,forexample,canbeatimingtriggerorauserinteraction.
Kerneltakescareoftimingtheeventcalls.Itcanautomaticallymaintainbothrunonceandrunrepeatedlyeventssimulteneously.
SinceKerneliskeepstrackofwhicheventneedstohappennext,butstillusingdelayMicroseconds,bettertimingprecisionandconsistencyisachived.
OtherPotentialBenefits
SinceaKernelissuchaadvancedframework,withalittleadditionalprogramming,somereallyusefulfeaturescanbeadded:
Itcouldkeeptrackofhowlongatasktakestocomplete,orgivemoreimportanttaskspriorities,andfactorthatintodecisionsofwhichtaskcangowhen,
likeatruekernelwouldforprocessmanagement.
Asingle"background"processcouldberun,withoutinterferingtoomuchwiththetimesensitivetasks.WhichcouldbeaccomplishedwiththerunNow
method.

HowitWorks
Thereisaqueueoffunctions.Theyareintheorderedchronologically.Sinceitisalinkedlist,thefunctionscanbeinsertedinbeforeotherfunctions,but
afterothers.
NowallthatKerneldoesislookatthenexttaskcominguptoseeifitistherighttime.Ifitisnottimeyet,itwillusedelayMicrosecondstogiveitaprecise
starttime.
Repeatingevents(calledintervals)willthenbereaddedtothequeueinthecorrectchronologicalorder.
Sincethesoonesteventisalwaysinthefrontofthequeue,noeventswillbepassedoverwhileusingdelay.

BasicUsage
First,downloadthekit kernelTest.zip.ItincludesKernel(GPLbyme),fastDelegate(PublicDomainfromCodeProject),amodifiedversionofthe
QueueListlibrary(fromtheArduinoPlayground),andasimpleArduino.inofiletoshowsomebasicusage.
Theusageisintentionallyverysimilarjavascript,whichusessetIntervalandsetTimeoutforrepeatingandonetimetasksrespectively.
//mayneedtouse<>insteadof""
//dependingonifyouinstalledKernelasalibrary.
#include"kernel.h"
Kernelkernel;//thisshouldbeaglobal,sootherfilescanuseittoo.
voidtest(){
Serial.println(micros());
}
voidsetup(){
Serial.begin(19200);

//addafunctiontointerval.Itwillrunevery10,000microseconds.
kernel.setInterval(10000UL,test);//ULmeanstheunsignedlong
}
voidloop(){
//shouldavoidanycodethatcouldcausemuchdelayhere

//runNextdecideswhethertodelayorrunthenextfunction
kernel.runNext();
}

That'sit!Inalotofways,it'sevencleanerthanaMetro.Ofcourse,thereisalotmoregoingonunderthehood.
Thisaboveexampleshowshowtoaddaninterval.ItisalsopossibletoaddatimeoutbyusingsetTimeoutinstead,whichwillonlyhappenonce.
SidenoteaboutUnsignedLongs(UL)
Intervalsandtimeoutsaresetinmicroseconds.Sincemicrosecondsaddupsoquickly,Arduinodealswiththemasunsignedlongs,buttheystilloverflow
(gobacktozero)afterabout70minutes.ThesetIntervalandsetTimeoutfunctionstakedurationsinmicrosecondsstoredinunsignedlongstoo.Sometimes,
itmightbenecessarytosaythatthewhatthetypeoftheconstantyouhaveinyourcodeis.Forexample,ifyouaredividingnumbers,youmightpreferto
usea2.0insteadofa2,sincea2isanintegerandmighttypecasttheothernumberintoanintegeralsoremovingthedecimalprecision.Similarly,
problemsmightormightnothappenwithverylongnumbersrepresentedbylongandunsignedlong.Argumentswillbytypecastintoanunsignedlong,so
itwillprobablynotbenecessarytospecify"UL"attheendofyournumbers.

AdvancedUsage
Removeatask
BothsetIntervalandsetTimeoutreturnauniqueintegerPID.Itcanbeusedtolaterremoveataskfromthequeue.
intnewPID=kernel.setInterval(100000UL,test);
kernel.clearInterval(newPID);

http://roboticcontrols.com/book/export/html/10

11/22

4/4/2015

Arduino

Removealltasks
Perhapsallcurrenttasksneedtostophappening.Maybeyou'vecomeaccrossanerrorandwanttostopeverything.
kernel.stopALL();

BreakUpaLongTask
Sure,youcouldcreateaseperatetaskforabackgroundtask,butifyourlooprunsquicklyenough,youcanessentiallyrunkernellikeyoumightaMetro,
exceptitisonlycheckingthenextpendingtask.
voidloop(){
for(intindex=0;i<hugeArray;i++){
//dosomeoperations

//willnotdelayuntilnexttask,tasksmaybeoverdue
kernel.runNow();
}
}

YouneedtodoeitherrunNow()frequently,ordorunNext()attheend.Otherwise,noeventswillbecalled.
Attachments:
kernelTest.zip

ClockDisplayWithoutSerial
Introduction
ThisisatutorialonhowtobuildaclockdisplayusingonlyanArduino,aShiftRegister,and4digitsevensegmentdisplay.
Theendresultshouldlooksomethinglikethismess:

Inthisimage,youcanseeanaccelerometertotheleft,whichisnotapartofthistutorial.

Clearly,thewholethinggetsverymessy.Asaresult,Iwouldrecommendonethatworksbyserial,offloadingthiswiringandrefreshing.Thereisagreat
ArduinobasedonebySparkfun,andacheaperoneavailableatAdafruit.It's$10$13fortheserialones,butthesebaredisplaysare2$,theshiftregisteris
3$forapackofthree,usesatabout20breadboardwires,8pinsonyourArduino,andrequiresthattheArduinobeabletocyclethroughthedigitsofthe
displayfrequently.Theextracostisminimalandsavesalotofeffort.

PartsList
.39inch4digit7segmentdisplay(BLQ39A42UG21fromAdafruit)
74HC595ShiftRegister(boughtfromAdafruit)
ArduinoUno
4x220resistors
Lotsofbreadoardwire

PinoutofDisplay
Ihadsometroublegettingthedisplaytoworkaccordingtothespecsheet,soIjustreverseengineeredit.

http://roboticcontrols.com/book/export/html/10

12/22

4/4/2015

Arduino

Thenumbersonthedigitsegmentsareintheorderofnegativeandpositive.So,tolightuptheleftmostdigit,0mustbenegative(grounded),andeachof
thesegmentscanbelitwithbygivingeachoftherightmostletteredpinsapositive.Asaresult,thegroundingpinmustbecycled,andtheotherdigitsmust
bepositive.Also,apparentlythe0andgpinsareinterchangable.

WiringDiagram
ImadeawiringdiagraminFritzing.Evenlikethis,itstilllooksdaunting,butatleastyoucantellwhatgoeswhere.

Icouldn'tfindsomethingfora4digitsevensegmentdisplaythathas8pinsoneachside.So,Ijustusedtwo7segmentdisplaysoverlayedsotheyhadthe
rightnumberofpins.Itlooksugly,butpretendit'sok.Thewiresshouldstillbethesame.
ThesvgandFritzingfilesareattachedatthebottomaswellforyourconvenience.

Code
Thecodeisalsosomewhatcomplicated.Therearetwomainproblems:convertingacharactertoaamapofonoroffvaluesforeachpin,andthefactthat
thedisplayhastoberefreshedeverfewmilliseconds.Itookcareofbothproblemsbywrittingmyownclass.Itshouldactuallybeuniversalforall7
segmentdisplayswithminimaladjustment.IwroteittoutilizetheKernellibraryImadesothatthetimingisnonblocking.
The.inofile:
#include"kernel.h"//handlestiminginnonblockingway
#include"SevenSeg.h"//mapscharacterstopinoutsonshiftregister
//declaresomeglobalinstancesoftheclasses
Kernelkernel;
SevenSegsev;
intcount=0;
voidincrement(){
sev.display(count);
count++;
if(count>9999){
count=0;
}
}
voidsetup(){
//setupthesevensegmentdisplayclass
sev.setup();
sev.setShift(8,12,11);//whichpinsthe
sev.setDigits(7,6,5,4);
sev.setSegmap(0,1,2,3,4,5,6,7);

//takesanUnsignedLong(UL)forthemicrosecondsbetweenintervals

http://roboticcontrols.com/book/export/html/10

13/22

4/4/2015

Arduino

kernel.setInterval(100000UL,increment);
}
voidloop(){
kernel.runNext();
}

TheSevenSeg.hclass:
TheSevenSegclassshouldbeuniversal,butyouhavetodoafewthingstosetitupfirst.
First,youneedtotellitwhichpinstheshiftregisterison.Thisisfairlystraightforwardwith:
setShift(latch,clock,data)
Theargumentsshouldcorrespondtothespecsheetforyourshiftregister
latch:maybedenotedasST_CP,orRCLK
clock:maybedenotedasSH_CP,orSRCLK
data:maybedenotedasDS,orSER
Next,youneedtotellSevenSegwhichpinsareusedtotogglewhichdigitisbeinglitinthecycle.TheseshouldberealpinsontheArduinoaddressableby
digitalWrite.Thedigitsareinorderfromlefttoright.
setDigits(7,6,5,4)
Then,youneedtomapthedigitsofthedisplaytothepinsontheshiftregister
setSegmap(...)
Thevalueoftheargumentisthepinontheshiftregister.Theorderoftheargumentssayswhichsegmentitbelongstoaccordingtothis:
/*
055555555555554
005555555555544
0044
0044
0044
0044
066666666666664
166666666666663
1133
1133
1133
1133
112222222222233777
122222222222223777
*/

Conclusion
DownloadtheArduinocode:

sevSegTest.zip

Again.It'sareallyreallygoodideatojustgetonethatworksoverserial.
Attachments:
clock.fzz
clock_bb.png
sevSegTest.zip

ClockDisplayWithSerialSparkfun
Introduction
ThesesevensegmentdisplaysaremanagedbyanextraArduinoembeddedinthem.Asaresult,farlesswiringandcodeisrequiredforyourproject,sinceit
isallencapsulatedinthisnicepackage.Hereisthefinishedproject:

http://roboticcontrols.com/book/export/html/10

14/22

4/4/2015

Arduino

BasicWiring(I2C)
Thewiringisreallystraightforward.OnthetopsidesthereisanSDAandSCL,whichgotoA4andA5respectivelyonyour
ArduinoUno.IfyouareusingadifferentArduino,checkthedocumentationontheWirelibrarytoseewhichpinyoushould
use.
Onthebottomsides,thereisaplusandminus,whichshouldbehookeduptothe5VandGNDpinsrespectivelyonyour
Arduino.

ConnectThesePins:
Arduino Serial7Segment
A5

SCL

A4

SDA

5V

GND

BasicCode
Ibasedmycodeonthepublicdomaincodepostedbysparkfun.Iadded:
Numberformatting(spacepaddedtotheright)
Usesnprintftohandleoverflows
Funcitonfordecimalprintingusingfloats
Beware!FloatsonArduinoarereallyinnacurate.Iget0.01erroronjusta3digitnumber!
/*Serial7Segmentisanopensourcesevensegmentdisplay.
Togetthiscodetowork,attachaSerial7SegmenttoanArduinoUnousing:
A5toSCL
A4toSDA
VINtoPWR
GNDtoGND
*/
#include<Wire.h>
#defineAPOSTROPHE5
#defineCOLON4
#defineDECIMAL43
#defineDECIMAL32
#defineDECIMAL21
#defineDECIMAL10
//ThisisthedefaultaddressoftheOpenSegmentwithbothsolderjumpersopen
#defineDISPLAY_ADDRESS10x71
voidsetup(){
Wire.begin();//Jointhebusasmaster
Serial.begin(9600);//StartUSBserialcommunicationat9600fordebugprints
//Sendtheresetcommandtothedisplay
//thisforcesthecursortoreturntothebeginningofthedisplay
Wire.beginTransmission(DISPLAY_ADDRESS1);
Wire.write('v');
Wire.endTransmission();

//HighBrightness
Wire.beginTransmission(DISPLAY_ADDRESS1);
Wire.write(0x7A);//Brightnesscontrolcommand
Wire.write(100);//Setbrightnesslevel:0%to100%
Wire.endTransmission();
}
floatcycles=0.0;//TESTDECIMALSENDING
voidloop(){
cycles+=0.1;//incrementdecimal
Serial.print("Cycle:");
Serial.println(cycles);

i2cSend(cycles);//Sendthedecimaltothedisplay

delay(1);//averysmalldelaytopreventflickering
}
voidi2cSend(floatnumberToPrint){
intdecimalPlace=1;

//finddecimalplace,fixthepositionofleftmostdigittotheleft
if(numberToPrint<0){
i2cSend(int(numberToPrint*100));
decimalPlace=DECIMAL1;
}
elseif(numberToPrint<10){
i2cSend(int(numberToPrint*1000));
decimalPlace=DECIMAL1;
}
elseif(numberToPrint<100){
i2cSend(int(numberToPrint*100));
decimalPlace=DECIMAL2;
}
elseif(numberToPrint<1000){
i2cSend(int(numberToPrint*10));
decimalPlace=DECIMAL3;
}
else{
i2cSend(numberToPrint);
}

if(decimalPlace!=1){
Wire.beginTransmission(DISPLAY_ADDRESS1);//transmittodevice#1
Wire.write(0x77);//senddecimalcommand

http://roboticcontrols.com/book/export/html/10

15/22

4/4/2015

Arduino

Wire.write(1<<decimalPlace);//sendtheplaceusingbitshift
Wire.endTransmission();//StopI2Ctransmission
}
}
//Givenanumber,chopupanintegerintofourvaluesandsendsthemoverI2C
voidi2cSend(intnumberToPrint){
//usesnprintf.Itwillalignthenumbertotherightofthestring
//snprintftruncatesthenumberafterthefirstfewdigits
charstr[5];
snprintf(str,5,"%4d",numberToPrint);

i2cSendString(str);
//thenumberistoobigmarkthatitwascutoff.
if(numberToPrint>9999){
Wire.beginTransmission(DISPLAY_ADDRESS1);//transmittodevice#1
Wire.write(0x77);//senddecimalcommand
Wire.write(1<<APOSTROPHE);//indicatean"overflow"
Wire.endTransmission();//StopI2Ctransmission
}
}
//Givenastring,i2cSendStringsendsthefirstfourcharactersoveri2c
voidi2cSendString(char*toSend){
Wire.beginTransmission(DISPLAY_ADDRESS1);//transmittodevice#1
for(bytex=0;x<4;x++)//foreachofthe4characters
Wire.write(toSend[x]);//Sendthecharacterfromthearray
Wire.endTransmission();//StopI2Ctransmission
}

Documentation
HerearesomeotherlinkstoSparkFun'sdocumentation:
ProductPage:https://www.sparkfun.com/products/11442
Tutorial:http://www.sparkfun.com/tutorials/407
Code:https://github.com/sparkfun/Serial7SegmentDisplay

LongbasedDecimals
Introduction
Arduinohasfloatsthatareonlyaccuratetoabout67digits.Whencombinedwiththefactthatfloatscannotrepresentcertaindecimalvalueswell(like.1
or.3)becausetheyareexpressedasnegativepowersofbase2,youmayoftenseeerrorespeciallywhenfullvalueisprinted,ortheoutputistruncated
insteadofrounded.
Ihavewrittenaclassherethatbasicallystoresawholenumberintoalong.Similartoafloat,thereisevenan"exponent"fieldthatsayswherethedecimal
pointisinthewholenumber.Unlikeafloat,operationsaredoneinbase10(ontoabase2number).Inexchangefortheflexibilityoftruefloatingpoint
numberintherangeofpossiblevalues,wegaingreaterprecisioninthenearertozeroareatheareafirmlywithintherangeofthelong(2,147,483,648to
2,147,483,647).Thesmallerthelefthandside(LHS)ofthedecimalplaceis,themoreprecisionisavailablefortherighthandside(RHS)ofthedecimal.

Usage
Sofar,allIhaveisareallybasicclassthatonlyhandlestheconstrucorandthebareminimumneededforprinting.
#include"longDecimal.h"
voidsetup(){
Serial.begin(9600);
Serial.println("BEGINTEST:");

LongDecimaldec(131,158272);

Serial.print(dec.getLHS());
Serial.print('.');
Serial.println(dec.getRHS());

LongDecimaldec1(131,158272);

Serial.print(dec1.getLHS());
Serial.print('.');
Serial.println(dec1.getRHS());

LongDecimaldec2(12345678,158272);

Serial.print(dec2.getLHS());
Serial.print('.');
Serial.println(dec2.getRHS());
}
voidloop(){}

Output
BEGINTEST:
131.1582720

http://roboticcontrols.com/book/export/html/10

16/22

4/4/2015

Arduino

131.1582720
12345678.15

Class
Youmightbeabletofigureoutwhatisgoingonjustbasedonthedocumentationonthecodefortheclassasitis:
#include<Arduino.h>
classLongDecimal{
private:
longdecimal;//theleftandrightsideofdecimal
unsignedintdecimalPlace;//wherethedecimalisintheabovevariable

public:
//constructors
LongDecimal(longlhs,longrhs);
LongDecimal(floatf);

//typeconversions
longgetLHS();
longgetRHS();
};
LongDecimal::LongDecimal(longlhs,longrhs){
decimalPlace=0;

//shiftlhstotheleftinthelong
longlhsSpace=abs(lhs);
longrhsSpace=1;

//floattheLHSallthewaytotheleftofthelongmaynotbedesirable
while(214748364L>lhsSpace){//maximumlongdividedbyten
lhsSpace*=10L;

decimalPlace++;
rhsSpace*=10L;
}

//puttheLHSintothemaindecimalvariable
decimal=lhs*rhsSpace;

//floattherighthandsidetoalignwithLHS
//movesrightifnecessarylosingprecision
while(rhs>rhsSpace){

rhs/=10;
}
//movesleftifnecessary
while(rhs*10L<rhsSpace){
rhs*=10L;
}

//puttheRHSintothemaindecimalvariable
//addtothedecimalifpositivesubtractifnegative
if(lhs<0){
decimal=rhs;
}
else{
decimal+=rhs;
}

}
//shiftsdecimaltotherightuntilitisjustthelefthandsideofthedecimal
longLongDecimal::getLHS(){
longLHS=decimal;
for(inti=0;i<decimalPlace;i++){
LHS/=10;
}
returnLHS;
}
//removesthelefthandsideofthedecimalbysubtraction
longLongDecimal::getRHS(){

longLHS=getLHS();//removesRHS,butisshiftedright
//shiftbacktotheleft
for(inti=0;i<decimalPlace;i++){
LHS*=10;
}

returnabs(decimal)abs(LHS);
}

OrganizedEEPROMstorage
Introduction
EEPROMisapermanentmemory.ItwillremainevenaftertheArduinoisrestarted.Itcanbereprogrammedaround100,000times,soitissubstantially
lessresilientthantheflashstorageoraharddrive.Itisalsokindofslow(3msperbyte).TheArdionoUnohas1KBofEEPROM.
http://roboticcontrols.com/book/export/html/10

17/22

4/4/2015

Arduino

Thecompiledprogramisuploadedtoflashstorage(notEEPROM),whichisfasterandlarger.So,ifyoucan,itisbettertowritekeepasmuchaspossible
intheC++file.
SometimesitcanbeconvenientormorereliabletousetheEEPROM.YoucouldlogsensorreadingstoEEPROMsothatthedatawillstillbethereevenif
itlosespower.Alternatively,youcoulduseanSDshieldandgetmore,morereliable,andmoreportablestorage.
IfyouhavemultipleArduinosforaprojectthatdothesametasks,butwantawaytodifferentiatethemdespitehavingidenticalprogramming,youcould
flashanIDnumbertotheEEPROM.

SimpleUsage
Writer

Reader

Hereisasimplewriterthatjustwritesanintof123tothefirstbyteinthe
EEPROM:

ThisreaderisusedafterthewritertogetthevaluefromtheEEPROM:

#include<EEPROM.h>
intaddress=0;
voidsetup(){
Serial.begin(9600);

intvalue=123;
EEPROM.write(address,value);

Serial.println("Donewriting");
}
voidloop(){
}

#include<EEPROM.h>
intaddress=0;
voidsetup(){
Serial.begin(9600);

intvalue=EEPROM.read(address);
Serial.print("Read:");
Serial.println(value);
}
voidloop(){
}

StructuredandOrganizedStorage
AcooltrickinC++istosortofoverlayastructureontoanareaofmemorytakingadvantageofdatastructurealignment.Thisorganizationmethodisused
heavilyinfilemanipulation,forexample:readingabitmap.
Thecoolthingaboutthisisthatyoucanmixdatatypesandnothavetoworryaboutreadingthingsintherightorder.Aslongasthestructremainsthesame
whenyoureaditafteryouwriteit.
Youmightseethisstructexampleandwanttouseitasaseperateclassinaseperateheader,butIdidn'tdothatprimarilybecauseitdependssoheavilyon
thestructyoumake.Itisactuallypossibletomakeanencapsulatedversionofthisbyusingtemplates.Atemplateisawaytopickadatatypeforsome
elementsinaclass.Somegoodexamplesofwaystheyareusefularevectorsandlinkedlists.
Thisclassshouldonlybeusedonceinaprojectwithoutanymodification.BysimplyaddingafixedoffsettotheEEPROM.readandEEPROM.write
methods,multiplescouldbeused.
#include<EEPROM.h>
typedefstruct/****EEPROMSTORAGESTRUCTURE****/
{
//stuffinheregetsstoredtotheEEPROM
unsignedshortcount;/*Acountofvaluesstored*/
longsum;/*Arunningtotalofvalues*/
charstr[10];/*Astringlabel*/
intvalues[100];/*Arrayofvaluescollected*/
booleancomplete;/*aflagforwhethergatheringisfinished*/
}EEPROMSTORAGE;
//aclasstomanagethestruct
classPermanent{
private:
//theactualeepromgetsstoredhere
//thestructisoverlayedontothisstorage
bytebuffer[sizeof(EEPROMSTORAGE)];
public:
Permanent();//constructorreadstheeeprom
voidwrite();//afunctiontowritetotheeeprom

//thispointermakesthebuffer'scontentseasilyaccessed
EEPROMSTORAGE*store;
};
//readtheeepromintothebuffer
Permanent::Permanent(){
for(inti=0;i<sizeof(EEPROMSTORAGE);++i){
buffer[i]=EEPROM.read(i);
}
//overlaythepointertothestorageontothebuffer
store=(EEPROMSTORAGE*)buffer;
}
//writethebufferintotheeeprom
//becarefulwrittingtoooftentotheeeprom.Itonlyhas100,000writes
voidPermanent::write(){
for(inti=0;i<sizeof(EEPROMSTORAGE);++i){
EEPROM.write(i,buffer[i]);
}
}
//makeaninstanceofthemanagingclasscalledeeprom(inlowercase!)

http://roboticcontrols.com/book/export/html/10

18/22

4/4/2015

Arduino

Permanenteeprom;
//thisisjustademoofhowyouwouldaccessandwritethedata
voidsetup(){
Serial.begin(9600);

//checktoseewhatwasalreadyintheeeprom.serialprintit.
Serial.println(eeprom.store>str);

//fillthebuffer'sstorewithsomedata
eeprom.store>count=0;
strcpy(eeprom.store>str,"Hello!");

for(inti=0;i<50;++i){
intsensorVal=i*3+2;
eeprom.store>values[i]=sensorVal;
eeprom.store>sum+=sensorVal;
eeprom.store>count++;
}
eeprom.store>complete=true;

//writethebuffereddatatotheeeprom
eeprom.write();
}
voidloop(){}

BlenderArduinoModel
Results
IcouldnotreallyfindanygreatBlendermodelsoftheArduinoUnoontheinternet,soIdecidedtomakemyown.
Minewasmadeentirelyfromscratchanddoesnotuseanyimagetextures(exceptthewoodinthisdemo).Itfeatures
mostofthedetailsoftheUno,butdoesnothavetheprintedcircuitry.Itwasmodelledoffanimageandsome
eyeballingforsizes,soitmaynotnecessarilybetoscale,butitlookscloseenoughforBlenderwork.Eventhetextis
there,usingthedefaultBlenderfont.TheArduinologoisactuallyameshofacircle.Themostnotablechipshavethe
propertextonthem,andtheplugsevenareshapedlikesockets.

Seethebottomofthispostforthe.blendfiles,orreadmoretoseehowitwasdone.

Progress
Ikeptrendersfromeachofthestepsalongtheway.Iwilldescribeeachsetofrenderswithaparagraphforeachrenderinlinefromlefttoright.

So,Istartbytracingtheboardfromanimage,whichwasactuallyeasy.Then"loopcutandslide"wasdoneseveraltimestosquareofftheholes.Oncethe
squareholesaremade,thesubdivisionmodifierisapplied.Theedgesonthetopandbottomofthesquaresmustbehardentwithshift+e,otherwiseitwill
lookmorelikeaworndownareathanadrilledhole.TheUSBconnectionwaseasy.Pickingtherightmaterialforitwastheimportantpart.Itshouldbe
reflectiveandstillhavesomeroughnesstoit.Justonepinwasmade,thenanarraywasusedtoduplicatethepininarow.Thendifferentsetsweremadeby
Shift+Dforduplicate.
Thepowersocketwaseasy,withjustacube.Extrudeonefacetwiceoncebiggerthenanotherthesamesize.Thensubdivisionsareappliedtogivethe
backendtheroundedlook.Alledgesbutthetopbacktwoshouldbeattheirhardestwithshift+e.TheATMEGAisactuallyreallyeasytodoexceptfor
thepins,whichneverquiteseemtolookright.
Istartedtryingtoaddthecapacitorsandthepiezobyusingcylenders,butthatwasthewrongwaytogoaboutit.Subdivisionsarealoteasier.
http://roboticcontrols.com/book/export/html/10

19/22

4/4/2015

Arduino

Irealizedthataddingthetextwasgoingtobereallyimportanttomakingitlookright.Itwasactuallyeasyenoughtoadditinexactlytherightplacesdueto
theuseofa"backgroundimage"onthecamera.Wheninwireframemode,youcanseeboththetextandtheimageyouaretracing.Thefontisclearly
wrongwhenlookingatthecomparisonimage,butitisnotsoobviouslywrongwhenjustlookingattheseimages.ThebiggestdifferenceisthattheIis
supposedtohavethecapsonit.TheLEDswereaddedandturnedon,justbecausetheycouldbe.Itwaslaterpointedoutthatitwouldbeimpossibleforan
arduinotohavebothonatthesametime.
Thearduinologoissimplyacirclemeshextrudedinward,thendeformedalittlebit.Here,Ialsofixedthecapacitorandpiezotousesubdivisions,and
addedtheaccuratenotchesandprotrusionstoeach.Ireallylikethewaytheblacktextonthecapacitorslooks.Again,theblacksideisjustacircle.

OfcoursetheArduinoneedsthetextontheATMEGAchip!.Ialsoaddedsomeblackboxesforthesmallerchipsthatarescatteredontheboard.Here,a
couplemoreblackchipsarebeingaddedtotheboard.
Here,IaddedthesocketstotheUSBandPowerblocks.Theydidnothavetheinteriorpartsbefore,butyoucouldn'tseethat.Istilldon'treallyliketheway
theinterioroftheUSBsocketlooks,butIdidn'treallycareasmuchaboutthatfeature.
Ialsowantedtoaddallofthelittleresistorsandtinycomponentsthatlittertheboard,butdecidedtotesthowjustthisoneworksbeforeduplicatingit.I
alsotweakedthematteplastictextureabitbymakingitsspecularlessintense.

Ithenduplicatedtheresistorsallovertheplacewherevertheywereneeded.Thepinsthat...well,actuallyIdon'tknowwhatthoseonesthatprotrudedoI
haveneverusedthem.Anyway,theywereeasyenoughtomakeIdidn'tevenuseanarray.Ijustduplicatedthem.
Andofcourse,theresetbuttonhadtobeadded.Thatwasjustaboxwithasubdividedboxontop.Ialsoaddedconnectingsoldertoabunchof
components.It'ssupposedtobemildlyreflective,sinceitusesthesamematerialasthecapacitors,butitneverreallyshowsinthesedemosprobably
becausethereisnoskymap.

CyclesTests
CyclesisanextgenerationrenderingengineinBlender.Itiscompletelydifferentthanthecurrentrenderer,sothematerialsandtexturessystemisentirely
differentanddoesn'ttransferbackandforth.Intheory,itissuperiorduetothefactthatitalllightbouncesoffthingsontoothers.Forexample,ifyouhavea
lightinyourhomethatpointsupwardtowardtheceilingaslongastheceilingisalightcoloritwillstilllighttherestoftheroomsincethelightbounces
offtheceilingtoo.Thedefaultblenderrenderdoesnotdothisbydefaultbutcanbemadetowiththeindirectlightingfeature.
IstruggledwiththeenvironmentlightinginCycles.Theworldmaterialmadeahugechangeintheoveralllighting,andnomatterwhatItriednothing
seemedtolookquiteright.However,thecomponentsthemselvestendedtohavemuchbetterlooksincycles.Ialsodecidedtoswitchtoaglossydemo
surfacejustbecauseItsortoflooksnicewithit'sreflectivity.Insomeways,theserenderslooknicer,andinsomewaystheylookwayworse.

Really,convertingittocycleswasassimpleasjustenabling"usenodes"onallthematerialsandthenchangingittoglossyinmostcases.Verylittle
tweakingwasneededwiththeexceptionoftheLEDs,whichneededtobeemissiontypes,buttheydidn'tlookquiterightwhentheywerejustemitting,soI
mixedanemissiontypewitharegularonesothatitwaslookedalittlemoreinplace.
IsortofwishthattheLED'slookedbetterthantheydo.Theyglow,buttheydon'treallylightuptheirsurroundingsasmuchasIwouldlike,whichismade
extremelyobviousbythedimenvironmentlightingIsettledwithincycles.
Attachments:
http://roboticcontrols.com/book/export/html/10

20/22

4/4/2015

Arduino

arduino.blend
arduinocycles.blend

LCDSainsmartHD44780/LCD2004
Introduction
ThisisaverysimpleLCDdisplaythathasatwowireserialinterface.Itdisplayscharacters,notpixels.Itcanshow20charactersinarowand4rows.They
arefairlyinexpensiveatretailonlyabout$10.Theyhaveatoggleablebacklightandavariablecontrast.

Wiring
Theserialcontroller(orbackpack)takes5V,soconnectthe5VandGNDtothe5VandGNDontheArduino.TheSDAandSCLpinsaretrickier.
DependingonyourArduino,itcouldgoanynumberofplaces,asseeninthetableattheright.
Arduinoi2cPins
Board

SDA SCL

Uno

A4

A5

Mega2560 20

21

Leonardo

Due

20

21

ThemostcommonboardistheUno,andthewiringofitcanbeseenhere.WhereSDAisthebluewireandSCListhegreenwireasisconvention.

Coding
Thiscodedisplaystheinformationshowninthepicturesabove.Itrequiresthatyouhavesomelibrariesinstalled.IhaveattachedtheversionIusedfor
convenienceandpreservation.However,thelibraryisoriginallyavailablefromhere,andamoreuptodateversionmaybeavailablethere.
ThelibrarymustbeinstalledinyourArduinofolder.Thefolderlocationis:
Windows %HOMEPATH%/MyDocuments/Arduino/ibraries/
OSX

~/Documents/Arduino/libraries/

Linux

~/Documents/Arduino/libraries/

DownloadtheLiquidCrystallibrary.zipfolderandextractthewholefolderintothelibrariesfolderforyoursystemabove.
#include<Wire.h>
#include<LiquidCrystal_I2C.h>

http://roboticcontrols.com/book/export/html/10

21/22

4/4/2015

Arduino

#defineI2C_ADDR0x27//DefineI2CAddresswherethePCF8574Ais
//AddresscanbechangedbysolderingA0,A1,orA2
//Defaultis0x27
//mapthepinconfigurationofLCDbackpackfortheLiquidCristalclass
#defineBACKLIGHT_PIN3
#defineEn_pin2
#defineRw_pin1
#defineRs_pin0
#defineD4_pin4
#defineD5_pin5
#defineD6_pin6
#defineD7_pin7
LiquidCrystal_I2Clcd(I2C_ADDR,
En_pin,Rw_pin,Rs_pin,D4_pin,D5_pin,D6_pin,D7_pin,
BACKLIGHT_PIN,POSITIVE);
voidsetup(){
lcd.begin(20,4);//20columnsby4rowsondisplay
lcd.setBacklight(HIGH);//Turnonbacklight,LOWforoff
lcd.setCursor(0,0);//gotothetopleftcorner
lcd.print("roboticcontrols.com");//writethisstringonthetoprow
lcd.setCursor(0,1);//gotothe2ndrow
lcd.print("HD44780/LCD2004");//padstringwithspacesforcentering
lcd.setCursor(0,2);//gotothethirdrow
lcd.print("20x4i2cdisplay");//padwithspacesforcentering
lcd.setCursor(0,3);//gotothefourthrow
lcd.print("Testincrement:");
}
intn=1;//aglobalvariabletotracknumberofdisplayrefreshes
voidloop(){
lcd.setCursor(16,3);//gotocol16ofthelastrow
lcd.print(n++,DEC);//updatethedisplaywithanewnumber
//overwritespreviouscharacters
//besurenewnumberismoredigits
delay(500);//waithalfasecondbeforeanotherupdate
}

Attachments:
LiquidCrystal.zip

http://roboticcontrols.com/book/export/html/10

22/22