1

Sous-vide: Mad og elektronik i én skøn forening

Sous-vide: Mad og elektronik i én skøn forening…

Sous-vide er lige som “low and slow” med grillen en teknik der fascinerer mig. Det går helt enkelt ud på at vacumpakke det og så tilberede det i varmt vand i mage timer. Vandtemperaturen vælges efter hvilken temperatur kødet skal ende på. Som med low and slow giver man med langtidstilberedning kødet mulighed for at nedbryde fibrene så kødet bliver utroligt mørt.

Såe… sår’n en dims må jeg da ha’ 🙂

Man kan selvfølgelig bare købe den færdig (se eks. her: link). For omkring 2500 kr er man i gang. Men nu er jeg jo både nørdet og nærig :-). Jeg har nu godt nok købt en vacuumpakker. Så fokus for denne blog er at bygge en Arduino-baseret temperaturstyring.
Der er følgende elementer i min sous-vide gryde:

  • sous-videTemperaturmåling
  • Styring af varmelegeme
  • Cirkulation
  • Temperaturregulering
  • Display / setpoint-justering
  • Kar

Denne blog handler om elektronik og firmware – senere kommer en anden om mekanikken.

Temperaturmåling

20160305_165649Jeg har købt en vandtæt temperaturføler. Den indeholder en DS18B20 (link) Maxim 1-wire temperaturføler – altså et digitalt serielt interface. Jeg lavede i sidste indlæg en gennemgang af sensoren og dens interface – så derfor se her: link.

Der viste sig dog nogle problemer med sensoren da jeg byggede den første mockup… 230V delen af projektet smadrede simpelthen one-wire bussen fra tid til anden. Jeg lavede derfor et simpelt filter der kasserer målinger der afviger mere end 5 grader fra den forrige måling. Det virker hæderligt omend der stadig slipper en ukorrekt måling igennem fra tid til anden. Der er absolut plads til forbedring.

Styring af varmelegeme

solid-state-relayVarmelegemet er faktisk bare en dyppekoger der er forbundet til et relæ. Eller faktisk er det ikke et relæ men et solid-state relæ. Et solid state relæ er en switch baseret på enten thyristorer eller FET-transistorer.

 

20160227_195153Så – faktisk bare et relæ med mindre strøm til trækspolen og mindre larm :-).

Denne her kan styre 230V / 2A load med et 5V styresignal. Da varmelegemet jeg skal styre er på 300W (~300W/240V=1.25A) er det helt fint.

Søg efter “Solid-State Relay 2A” – den koster omkring 0,99 GBP.

Signalet er active low – så 0V er tændt og 5V er off. Og i softwaren er det eneste jeg skal tænke på at sætte den port jeg vælger til et output og så ellers sætte den on/off:

…MEN…AAAGRHHH… De solid state relæer jeg havde fået virker ikke… Jeg testede to stk… Heldigvis stoppede jeg der – og blev opmærksom på at min dyppekoger ikke var 300W (1.25A) – men 500W (2.1A)… lidt googling viser også at man ikke kan stole ret meget på de 2A de er rated til… Det er nok ikke Omron der er inden i trods det der står printet uden på…

Jeg testede en ny med en 40W el-pære – og så virkede den pludselig meget bedre…

Men – det løser jo ikke opgaven. Heldigvis havde jeg også købt nogle 10A solid state relæer – så det endte med sådan en i stedet. De er så active high – så high på udgangen give tændt heater.

Styring af cirkulation

6v 30 rpm motor“Rørepinden” drives af en gearmotor jeg har fundet på ebay. Det er en 6V DC-motor der kører med 60 omdr/min. Arduino’ens ben kan ikke trække strøm nok så jeg har brug for et eller andet til at drive motoren.

Rørepinden skal egentligt køre hele tiden – så måske skulle jeg bare sætte den direkte på strømforsyningen… Meeen omvendt vil jeg egentligt gerne kunne starte og stoppe den langsomt så det ikke skvulper så meget… Og til det formål vil det være smart med en PWM udgang.

fetOg – hov! Nederst i bunken af stumper fandt jeg et IRF520 baseret modul – det er godt nok en 9.2A fet… men det er vist fint nok :-)… Man skal dog lige huske at sætte en diode over motorterminalerne så man ikke risikerer at motoren “sparker igen” når man slukker FET’en. Årsagen til at en motor gør det er dels at der er en spolevirkning  i viklingerne der forsøger på at holde strømmen konstant – og med open circuit så øger den spændingen for at forsøge at få strømmen til at løbe. Desuden “vender” motoren om og bliver en generator når man afbryder den og den bremser op. Den strøm motoren genererer skal kunne  løbe et eller andet sted hen – ellers får man samme effekt med høje spændinger. Og har man høje spændinger så er det bare et spørgsmål om hvad der går i stykker først… 🙂

I firmwaren er det eneste der er nødvendigt at skrive en analog spænding til den PWM-udgang man vil bruge. Hvis man kan leve med 1kHz pwm-frekvens så er det en nem måde at lave PWM-styring på… Så jeg slipper i denne omgang for at tilpasse det H-bro library jeg lavede til robotbilen (link).

Der viste sig i praksis at være nogle mindre problemer med den opstilling… Nemlig at 60 omdr/min slet ikke er nok til at få vandet til at cirkulere. Jeg satte en strømforsyning i serie med motoren – så den fik omkring 12V i stedet for 5V… Og det hjalp. Så – nu har jeg bestilt en motor med en højere gearing – måske for høj men så kan jeg jo reducere den med PWM’en.

Temperaturregulering

Temperaturreguleringen har jeg i første omgang lavet som en helt simpel bang-bang regulering. Det vil sige at jeg tænde varmelegemet hvis temperaturen er 0,5 grader under setpunktet og slukker det når temperaturen er 0.5 grader over setpunktet. Det har vist sig at virke bedre end forventet – men når jeg får analyseret på opvarmningskurverne så vil jeg vurdere om jeg skal gøre noget ved det.

Display / temperaturjustering

20160402_162310Jeg har købt et 2×16 LDC keypad shield – altså et print med display og knapper der passer lige ned på Arduinoen. Og det er f… fikst 🙂
Det almindelige arduino LCD-library (LiquidCrystal.h – link) virker perfekt. Shielded bruger pin 4-9 – så det eneste man skal gøre er at oprette objectet med benene som parameter på constructoren. Derefter kalde “begin” med størrelsen af displayet – her 2×16 tegn. Endelig er det bare at gå i gang…:

 

Nu er der jo også nogle knapper… De er sat på med en spændingsdeler så hver knap repæsenteres af en spænding som kan måles med en analog indgang. Med en 10 bit ADC er der 2^10 mulige værdier – altså fra 0-1023:

Key Voltage ADC
right < 6% <61
up 6 – 20% <205
down 20-40% <410
left 40 – 60% <614
select 60-80% <819
none 80 – 100% >819

så:

 

Hvis man ikke gør andet vil koden tro at man har trykket på en knap hver gang man kalder funktionen (altså mens man holder knappen nede). Det vil i praksis betyde a knappen repeterer med en ukendt hastighed. For at undgå det har jeg lavet en stump ekstra kode der både sørger for at ét tryk kun giver respons én gang OG sørger for at repetere med en kendt hastighed:

Tilgiv at ovenstående kode er lidt rodet – jeg har lavet det som en klasse der oprettes og kaldes gennem sit interface. Se kode-linket herunder.

Strømforsyning

Jeg har købt nogle små 5V / 2A strømforsyninger. Simpelt og nemt :-).

Diagram

2016-04-23

Firmware

Jeg har ad flere gange optimeret lidt på koden – både UI, struktur og funktionalitet. Konkret er der kommet et ur til, koden er blevet strukturet bedre og jeg fik fikset nogle læsefejl fra temperaturføleren.

Du kan hente arduino-imaget her:  Download

Summary – og test 🙂

20160305_165639Skrue skrue skrue… Og voila blev konstruktionen sat sammen.

20160404_212406Første udgave var som nævnt voldsomt ustabil. Temperatursensoren gav fejlmålinger og koden gik ned med jævne mellemrun :-). Det opdagede jeg på den hårde måde ved første test 🙂 Koden crashede med varmelegemet tændt – og vandet nåede op på 80-90 grader. Det var lidt mere end plastikkarret kunne holde til – så det buler lidt nu… Godt jeg havde stillet den i vasken!!!

20160404_212301Jeg fik så det hele bygget lidt mere permanent sammen – med en mere hensigtsmæssig kabelføring og klar adskillelse af 230V og 5V. Det hjalp. Så forleden lavede jeg første test med en enkelt bøf 2 timer ved 54gr og dagen efter med en tyndsteg 11 timer ved 57gr. Begge var fine resultater – omend stegen var mere gennemstegt end jeg selv foretrækker :-).

20160403_160619




DS18B20 – om en temperatursensor, 1-wire og 2’ers komplement binær matematik

I en del af mine forrige posts harjeg mixet detaljerne ind i de enkelte projekter og der har gjort det lidt svært at referere til dele senere… Så jeg prøver nu at skille de lidt tungere dele ud af projekterne…

DS18B20 er et “Programmable Resolution 1-Wire Digital Thermometer”. I al sin enkelthed er det en temperatursensor med konfigurerbar opløsning og 1-wire interface.

1-wire

1-wire er en standard som Dallas Semiconductors har lavet (de er senere blevet købt af Maxim). Det er en simpel bus der gør det muligt at have mange enheder på samme få ledninger. Man behøver faktisk kun to – signal/forsyning og gnd. Der er dog en del devices der helst skal have særskilt forsyning. Hvis man vil drive enheder “parasitisk” (altså uden en ledning til forsyning) så skal porten vendes til et output og drives høj når man ikke kommunikerer.

Der er en app-note (link) der beskriver detaljerne hvis man vil drive porten. Jeg valgte den dovne løsning – og fandt et library (link). Det er ikke et officielt Arduino lib – men det næstbedste – nemlig et Arduino Contributed library. Det betyder at det har en vis standard og Arduino promoverer det – men uafhængige vedligeholder det.

Der er dog et lille “men” ved det library – det er et “bit-bang” library. Det vil sige at når der skal læses/skrives/ventes på bussen så sker det direkte i kodeflowet – så er der en forsinkelse på 1ms – ja så venter alt andet på at det er klaret. Omvendt er det også positivt da det gør at man kan bruge alle pins – og ikke kun dem der er tilsluttet til nogle bestemte ben…

OneWire devices har en unik 64-bit id som man skal bruge hvis man har flere devices på samme bus. Til dette formål har onewire biblioteket en scan-funktion der kan vise hvilke devices der er på bussen. Jeg har lavet et lille program der kan detektere devices og udskrive deres “family name”. Det kan hentes her: Download.

DS18B20

DS18B20 har som omtalt programmerbar opløsning – 9-10-11-12 bit. Den måler med bedre end +/-0.5 grads præcision fra -10 til +85grader – men kan måle fra -128 til ca. +128 grader. Sensoren kan enten køre med “parasitisk” strømforsyning eller forsynes direkte.

En (vigtig) detalje som man skal være opmærksom hvis man kommunikerer med enheder der indeholder en  A/D converter er konverteringstiden. Årsagen er at en konvertering fra analog til digital kan tage meget lang tid. I DS18B20 i 12 bit mode tager en konvertering 750ms! Det skal man altså ikke stå og vente på for så kommer UI og alt andet til at føles helt ulideligt langsomt. Heldigvis kan man konfigurere den til et lavere antal bit – og så tager konverteringen markant kortere tid – en halvering per bit man undværer (det er en successive approximation converter). Måske kommer den en blog om A/D-konvertering en anden dag :-). 9-bit konvertering tager max 94 ms. Men uanset bør man designe sin software så andet kan ske mens man venter på A/D-konverteringen.

Man styrer kredsen ved at starte konverteringen med en kommando. Derefter kan man enten vente et antal milisekunder og så læse temperaturen. Eller man kan polle status for konverteringen – og så hente målingen når konverteringen er overstået. Outputtet er en 16-bit størrelse i 2’s komplement signed format…

Ok – det kræver vist en forklaring… Først lidt om binære tal generelt – og derefter om hvordan man håndterer negative tal.

Binære tal

Først – om binære tal… Det binære talsystem er bygget op som det decimale (10-tals baserede) med den forskel at basen er 2. I 10-talssystemet betyder første ciffer (altså første plads til venstre for decimalseperatoren – komma) antal “enere” (100), 2. ciffer er antal 10’ere (101), 3. ciffer er antal 100’ere (102) etc. I det binære er første ciffer antal 1’ere (20), 2. ciffer er antal 2’ere (21), 3. ciffer er antal 4’ere (22). Dvs. mindste tal er 0 og største tal er 2n-1. Eks. 137 som binært 8-bit tal:

Vægt 27 26 25 24 23 22 21 20
Vægt 128 64 32 16 8 4 2 1
Bit 1 0 0 0 1 0 0 1
Værdi 128 8 1

128+8+1 = 136…

Negative tal i binært format – 1’ers komplement

Nå – men hvad så med negative tal… Dem repeæsenterer vi decialt normalt bare med et “-” fortegn. Det kunne man sådan set også godt gøre for binære tal…. Man vil så bruge et bit som “sign-bit”. Konventionen er normalt at 0 er positivt fortegn og 1 er negativt fortegn. Metoden kaldes “eners komplement” og indbærer at der er både +0 og -0. Mindste tal er -(2n-1-1); største tal er +2n-1-1. Eks. -67 som 8 bit binært tal i eners komplement:

Vægt -1 26 25 24 23 22 21 20
Vægt -1 64 32 16 8 4 2 1
Bit 1 1 0 0 0 0 1 1
Værdi 64 2 1

-(64+2+1)=-67

Negative tal i binært format – 2’ers komplement

Det er dog ret besværligt at lave matematik med negative tal i eners komplement. Derfor opfandt man 2’ers komplement. Der er stadig et sign-bit – men dette signbit indgår også direkte i tallets højeste bit. det betyder at der kun er ét “0” og at mindste værdi er -2n-1; højeste tal er 2n-1-1. Eks. -67 som 8 bit binært tal i 2’ers komplement:

Vægt -27 26 25 24 23 22 21 20
Vægt -128 64 32 16 8 4 2 1
Bit 1 0 1 1 1 1 0 1
Værdi -128 0 32 16 8 4 0 1

-128+32+16+8+4+1=-67

Binær matematik

Men hvorfor er det smartere – altså ud over at man ikke behøver tænke over at der både  er +0 og -0…? Den nemmeste måde at forklare det på er ved en skive.

Hvis man eks skal summere to tal – eks. 3+4, er er det i 3-bit binær:

tal operator bit 2 bit 1 bit 0
2 0 1 0
+
3 0 1 1
5 = 1 0

(1 i mente)

1

Ok – det er ikke så nemt at vise summationen i en tabel her – men ideen er ligesom at addere i decimalt så får man en mente der flyder over til næste ciffer.

Men – hvad nu med negetive tal… Eks. 3 + -2 i 4-bit binært 2’ers komplement:

tal operator bit 3 bit 2 bit 1 bit 0
3 0 0 1 1
+
-2 1 1 1 0
 1 = 0

(1 i mente)

0

(1 i mente)

0

(1 i mente)

1

Som det ses ender svaret med at være korrekt selvom den sidste mente (1) ender med at være til overs. Som det er illustreret med bit 2 og 3 så betyder menten at fortegnet bliver ved med at være korrekt uanset hvor mange bit man arbejder med…

Et eksempel med negativt resultat: 1 + -3

tal operator bit 3 bit 2 bit 1 bit 0
1 0 0 0 1
+
-3 1 1 0 1
 -2 = 1 1 1 0

(1 i mente)

binary_circle2Så med andre ord virker helt almindelig “positiv” matematik på binære tal i 2’ers komplement. Men hvorfor egentligt det?

Hvis tegner talsystemet som en cirkel – som vist. Så svarer addition af et positivt tal til at flytte med uret. At addere et negativt tal svarer til at flytte mod uret. Eks. 1 + -3: Fra 0001 -> 0000 -> 1111 -> 1110 = -2.

Nå – sådan virker det altså – og det kan vi så herefter glemme alt om da både micro controlleren og temperatursensoren arbejder i 2’ers komplement 🙂

En dag skal jeg beskrive hvordan man kan opfatte binære tal som tal mellem -1 og +1 og derved opnå en række fordele når man laver matematik…

Output fra DS18B20

Nå – med den lange søforklaring er vi tilbage til outputtet fra A/D converteren. Af databladet fremgår det at kredsen giver følgende opløsning ved forskellig bit-opløsning:

Antal bit Opløsning Min Max
9 bit 0.5°C/bit -256
-128.0°C
+255
+127.5°C
10 bit 0.25°C/bit -512
-128.0°C
+511
+127.75°C
11 bit 0.125°C/bit -1024
-128.0°C
+1023
+127.875°C
12 bit 0.0625°C/bit -2018
-128.0°C
+2047
+127.9375°C

Så for at få temperaturen i grader celcius ganger man bare med 2n hvor n er opløsningen i bit…

DallasTemperature

Jeg fandt et library der hedder “DallasTemperature” (link). Det indeholder support for flere devices – og altså også DS18B20. Dokumentationen kan findes her: link. Download zip-filen fra github og udpak den i arduino\libraries folderen. Så kan compileren finde den. Der er et hav af eksempler med. Med dette library er det utroligt simplelt at få hul igennem:

Så med den nyvundne viden og funktionalitet er første step af mit sousvide projekt klar 🙂

 




Robotbil del 1 (Chassis / hjul / motor / motordriver)

Når man vil bygge en robotbil er der forskellige elementer man skal have styr på…

  • Chassis / hjul / motor
  • Motor driver
  • Hastighedsbestemmelse / obstackle detection
  • Navigation / intelligens…

Denne blog handler om Chassis, motor og motordrive

Chassis / hjul / motor

robotbilJeg fandt et kit på ebay – så det tænkte jeg var et godt udgangspunkt 🙂

Hvis du vil finde den på ebay så søg efter “Robot Car Chassis Kit”. Den koster 4-10 GPB.

Bemærk at en del af de kit man kan få er uden speed encoder skiverne. Det er lidt ærgerligt at få fat i et kit uden…

Den jeg bestilte var MED encodere… Desværre var de ikke med i kassen :-(. Jeg skrev til leverandøren og de ville sende mig et nyt kit – men med 20-30 dages shipping så får man jo gråt hår inden den dukker op…

Kittet inkluderer chassis, hjul, 2x gearet dc-motor, møbelhjul (forhjul) og speed encoder skiver.

20160213_203652Samlingen er fikst lavet så motorerne / hjulene bliver holdt af nogle plexiglasstumper.
Motor / gearkasse er fint integreret og ultra simple.

 

Motor driver

H-bro

2016-02-13 (2)Motoren er en 3-6V DC-motor. Det betyder at man kan bruge PWM (pulsbredde modulation) til at justere hastigheden og fortegnet kan vende retningen.

For at kunne justere både pulsbredde og fortegn så bruger man en såkaldt H-bro. En H-bro er et kredsløb som gør at hver side af motorviklingen kan sættes til hhv. 0V og 5V. Det samme kunne man jo principelt opnå ved at bruge to digitale udgange direkte – med den lille detalje at de digitale udgange ikke kan levere strøm nok til det…

2016-02-13 (5)Der er en lille detalje man er nødt til at tage hensyn til “i den virkelige verden”. Nemlig det at en transistor (eller FET) tager lidt tid om at gå fra on til off og tilbage igen. Som vist i billedet betyder det at både A og B er tændt samtidig i et kort stykke tid. Med andre ord er der det man kalder “gennemtænding”. Når der både er strøm og spænding samtidig vil der afsættes effekt i transistoren. Det holder de sjældent til i længden… En yderligere detalje er at de fleste transistorer og FET’er er hurtigere til at tænde end til at slukke.

Løsningen er at lægge et “dead band” ind. Altså et kort stykke tid fra den ene er sat off før man tænder den anden. Tiden er meget afhængig af transistor/FET valget – men ofte i omegnen af 1-2us.

Når man skal dimensionere sin H-bro har man brug for at vide hvor meget strøm motoren trækker. Man har dels brug for at vide hvad motoren trækker ved “normal” belastning – men også worstcase. Det værste der kan ske er at moteren bliver blokeret da det betyder at der er en kortslutning af motoren. Så er det kun den ohmske-modstand i motoren og forsyningens kapacitet der begrænser strømmen.

En hurtig måling med 6V og hhv. belastet og blokeret motor viser at strømmen er ca. 250mA ubelastet, 800mA tungt belastet, 1A lige før blokering, 1.3A blokeret.
L9110SJeg har købte nogle H-broer færdige på Ebay. Søg på “arduino L9110” og “arduino L298N”. Begge er 2-kanals hvilket vil sige at de hver har 2 H-broer og dermed kan styre to motorer.

L9110 kan drive 800 mA kontinuert (2A peak) på hver kanal. Forsyningsspændingen skal ligge mellem 2,5-12V.
L298N kan levere 2A continous, 3A peak, supply 2.5-46V.

Det fede ved begge moduler er at de klarer det praktiske omkring dødbånd – så det eneste vi skal er at sende en PWM til hver side af H-broen.

L298NTil denne applikation er det fikst at vi kan drive begge motorer med samme modul.

De markedsføres nogle steder som “stepper drivers”. Hvis man vælger at “håndstyre” stepmotorer kan man også gøre det med en enkelt af driverne. Personligt foretrækker jeg godt nok at slippe for at skulle styre pulstogene til stepmotoren – altså ved at bruge en driver der tager sig af det praktiske… En blog om stepmotorer kommer senere.

Nå – men den “lille” – L9110 – er helt fin til disse motorer – så den monterer jeg.

20160214_135035

L298N ligger på bordet ved siden af.

Hastighedskontrol – PWM

Helt kort om PWM – pulsbreddemodulation. Det går helt enkelt ud på at hvis man har et signal med konstant frekvens men varierer pulsbredden, så vil gennemsnittet blive afhængigt af pulsbredden. Det kan bruges til at bestemme lysstyrken på en pære eller lysdiode – eller justere hastigheden på en motor.

De 4 styresignaler er parvis inverterede – A og B i forhold til C og D. Tænder man både A og B (eller C og D) vil det give en kortslutning af forsyningsspændingen. Som nævnt håndterer hardwaren denne kompleksitet – så styringen kan nøjes med at fokusere på A og C signalerne.

Spændingen over motoren er differencen mellem A/B og C/D:

2016-02-13 (4)

Så – så længe broen er i 50% dutycycle på både A/B og C/D vil spændingen over motoren være 0V. Først når broen går “ud af balance” – altså at A/B siden kører med anderledes pulsbredde end C/D siden. Hvis A/B siden er mere “positiv” end C/D vil resultatet være at motoren oplever en positiv spænding. Omvendt hvis C/D-siden er mest positiv vil motoren opleve negativ spænding – og dreje “baglæns”…

Arduino PWM-kontrol

PWM funktionen er linket til ATmega processorerens timere. Jeg har ledt rundt – men det er ikke så nemt at finde et simpelt library… Der er nogle guides – men jeg tror at fordi der er så mange muligheder så er det svært at lave et ordentligt generelt library. OG det er nogle rasende avancerede enheder – så det jeg beskriver herunder er kun en lille flig af helheden – den flig jeg skal bruge 🙂

Der er tre timere i ATmega 328. De fleste funktioner virker på alle tre timere – så jeg bruger notationen “x” hvis det er underordnet hvilket register der vælges.

Det smarte ved at der er to compare registre per timer er at man kan få to ben til at vippe synkront – det skal vi bruge :-). Det man bruger når man skal have en timer til at virke som PWM-kanal er “output capture”-funktionalitet. Der er to compare registre – dem benævner jeg “y” når det ikke er vigtigt hvilket af registrene der anvendes. Output Compare går helt enkelt ud på at sammenligne et compare register (OCxy) med timerens værdi (TCNTx). Når de er ens sættes det tilknyttede “flag” (OCFxy). Afhængigt af settings for “waveform generatoren”  kan dette flag kobles sammen med et output ben – og voila har vi et PWM output.

Der er to PWM-modes: “Fast PWM” og “Phase correct PWM”. Forskellen er illustreret her.

2016-02-14

“FastPWM”: Tæller fra 0 til 255 og starter så forfra. Output Capture giver dermed ét skift per kanal per periode.

 

2016-02-14 (1)

“Phase correct PWM”: Tæller fra 0-255-0. Det betyder at der er to skift per periode per kanal. Perioden er dog den dobbelte af fast-pwm og det vigtigste er at outputtet er symmetrisk. Dvs. begge flanker flytter når output capture registeret ændres.

Phase correct PWM er fint i mange situationer – men uden betydning her – så jeg holder mig til Fast PWM.

MEN MEN MEN… Og det er så her bagsiden af Arduino rammer en i nakken hvis man ikke er opærksom… Arduino er før med et 1kHz interrupt der søger for at delay() funktionen virker. Dette interrupt hænger på timer 0 – så hvis man bruger den til pwm – og sætter frekvensen til andet end SCLK/64 – ja så vil delay() ikke give korrekte forsinkelser længere…

PWM outputs

Hver timer er relateret til nogle ben:

Timer Pins
0  5, 6
1 9, 10
2 3, 11

Register configuration

TCCRxA (Timer/Counter Control Register A):

7 6 5 4 3 2 1 0
COMxA1 COMxA0 COMxB1 COMxB0 WGMx1 WGMx0
1 0 1 0 0 0 1 1

Se herunder for detaljer om begge control registrene.

TCCRxB (Timer/Counter Control Register B):

7 6 5 4 3 2 1 0
FOCxA FOCxB WGMx2 CSx2 CSx1 CSx0
0 0 0 0 0  X  X  X

COMxy[1:0] – Compare output match; non-inverting: 0b10

WGMx[2:0] – Waveform generation mode; Fast PWM; 0-255 count: 0b011

FOCxy – Not used in PWM mode: 0b00

CSx[2:0] – Clock source; afhænger af den valgte timer (bemærk at det tager 256 cycles at foretage en komplet cycle):

Clock source Timer 0

CS0[2:0]

Timer 1

CS1[2:0]

Timer 2

CS1[2:0]

Off 0b000 0b000 0b000
SCLK/1 (62.5 kHz) 0b001 0b001 0b001
SCLK/8 (7812.5 Hz) 0b010 0b010 0b010
SCLK/32 (1953.1 Hz) NA NA 0b011
SCLK/64 (976.6 Hz) 0b011 0b011 0b100
SCLK/128 (488.3 Hz) NA NA 0b101
SCLK/256 (244.1 Hz) 0b100 0b100 0b110
SCLK/1024 (61.0 Hz) 0b101 0b101 0b111

TCNTx (Timer/Counter Register):

Momentan timer værdi. Timer 0 og 2 er 8 bit. Timer 1 er 16 bit.

Dette register skal man normalt ikke bruge i PWM-mode. Det kører frihjul af sig selv…

OCRxy (Output capture register):

PWM-værdi. Timer 0 og 2 er 8 bit. Timer 1 er 16 bit. 1 er en smal puls 255 (eller 65535 for Timer 1) er fuld bredde (all-on).

Strømforsyning

Dummefejl… Eller i hvert fald ubetænksomhed… Da jeg testede mit library snurrede hjulene fint – i 1-2 sekunder hvorefter printet rebootede…
Meeeen – nu var min opstilling strømforsynet fra USB… Og USB kan ikke levere motorernes startstrøm… Desuden havde jeg ikke sat nogen ekstra kapacitet (kondensator) på ude ved H-broen. Så alle strømtræk (dynamiske som statiske) skulle gennem Arduino-printets USB forsyning. Ikke smart.

20160220_092124Den dårlige undskyldning er selvfølgelig at jeg ikke tænkte på det fordi mit robot-kit blev leveret uden (ved en fejl)… Jammerligt dårlig undskyldning 🙂

Så – jeg hittede nogle forsyningsledninger til batterier…

C++ library

Såe… jeg har klappet et simpelt library sammen med det ene formål at styre én H-bro med to PWM-kanaler.

Du kan hente h-bro library’et (med eksemple) her: Download

Kernen i biblioteket er konfiguration og ændring af dutycycle. Her i en forsimplet kode:

Interfacet er en klasse (class):

Her en stump testkode der skifter fra -100% til +100% og tilbage igen:

Du kan ændre til timer 0 i linje 3.
Hastigheden der ændres med kan ændres i de to linjer med “sign=+/-10”.

Test af biblioteket

Testene er lavet med min USB-logikanalysator (se mere her: link).

50% dutycycle og så skulle jeg lige vise PWM signal analysatoren i Pulseview:

2016-02-20

Der er to lidt bemærkelsesværdige observationer her. For det første burde frekvensen være 976.6Hz (16MHZ/256/64) – men den er faktisk 1 kHz (freq = 1/periode; f=1/1ms=1kHz). Det er lidt uklart for mig hvorfor. Det må jeg lige grave i på et andet tidspunkt. Det andet interessante er at dutycyclen er 50.39Hz og ikke 50.00%. Årsagen er at dutycyclen for 50% er 128. 0 er 0%; 255 er 100%. Hældningskvotienten er alpha=100/255 så ved 128 får vi y=alpha*x= 50.20%. 127 giver 49.80%.

En del af fejlen skyldes dog også at jeg brugte for lille sample rate i pulseview…

Høj dutycycle:

2016-02-20 (1)

Varierende dutycycle -max til +max:

2016-02-20 (2)

Igen varierende – tættere på med PWM detaljer:

2016-02-20 (4)

 




Rotary encoder, gray code og kontaktprel

20160204_190250En af mine indkøbte dimser fra ebay er en “rotary encoder”.
Det er en dims der kan konvertere roterende bevægelser til digitale signaler. Den jeg har købt har 20 positioner på en omgang – og leverer output i to digitale pins der er “gray coded”.

Detekteringen sker mekanisk. Det betyder at det er kontakter der clicker ind og ud når man drejer akslen.

En udfordring ved den konstruktion er at mekaniske kontakter laver noget man kalder kontaktprel. Altså at kontakten hopper til og fra når den skifter position. På engelsk kalder man det bounching. Der er forskellige løsninger til at fjerne kontaktprel – på engelsk kaldes metoderne under et “de-bouncing”.

Der er en hel del mellemregninger – men jeg lover en (i min optik) lille lækkerbisken nederst.

Gray code

Gray code er en utroligt simpel men meget effektiv teknik der kan benyttes alle de steder hvor det kan give problemer når mere end ét bit ændrer sig ad gangen.

Et eksempel… binært 1 øges til 2:

01 -> 10

Lad os nu forestille os at vi læser de 2 bit af to gange. Første gang vi læser er lige før der lægges “1” til “01”. Bit 0 læses som “1”. Anden gang vi læser er lige efter opdateringen så nu er bit 1 = “1”. Når vi samler de to bit får vi “11” – og ikke “10” som er den korrekte værdi. Så – afhængig af hvornår man læser kan man få tre forskellige værdier hvoraf den ene er helt i skoven: “01”, “10” og “11”.

Nå – men hvad kan grey code da gøre ved det? Jo… Som nævnt er det smarte at kun ét bit ændrer sig ad gangen:

Index bit 1 bit 0 decimal
0 0 0 0
1 0 1 1
2 1 1 3
3 1 0 2

Så – i eksemplet fra før – så vil man når man går fra 1 -> 2 i stedet få:

01 -> 11

Så læsning før / efter vil give “01” eller “11” – uanset timing.

Gray code og rotary encoders

En anden anvendelse af gray code er ved rotary encoders hvor gray code kan bidrage til at afsløre hvilken retning akslen drejes i. Det kaldes også quadrature encoding. Det er baseret på to bit og mekanisk eller optisk afkodning af en kode-skive der sidder på akslen:

encode-skive

Hvis der placeres to sensorer (A og B) ved den røde firkant og man roterer skiven så kan de sorte og hvide felter oversættes til “ettere” og “nuller”.

Rotation med uret:

A 0 1 1 0 0 1 1 0 0 1 1
B 0 0 1 1 0 0 1 1 0 0 1

Rotation mod uret så får man:

A 0 0 1 1 0 0 1 1 0 0 1
B 0 1 1 0 0 1 1 0 0 1 1

Hvis man nærstuderer signalerne kan man se at når det ene eller andet signal ændrer sig så kan man bruge niveauet på den anden til at se hvilken vej der drejes:

Med uret: ↑A+!B og ↓A+B og ↑B+A og ↓B+!A

Mod uret: ↑A+B og ↓A+!B og ↑B+!A og ↓B+A

Så med gray code kan vi med to bit detektere rotation og omdrejningsretning.

Debouncing

Debouncing går i al sin enkelthed ud på at eliminere det kontaktprel som alle mekaniske kontakter laver:

Her et ikke nærmere specificeret eksempel der illustrerer hvordan kontakten hopper mellem åben og lukket.

2016-02-06 (2)

Udfordringen er at fjerne de falske on/off transitioner uden at forsinke signalet…

Det er en lidt umulig opgave – men den største del af problemet kan løses med et simpelt kredsløb som dette:

I al sin enkelthed går det ud på at bruge en kondensator til at forsinke ændringen i signalet indtil det er stabilt.

Når switchen er off vil modstanden lade kondensatoren op til forsyningsspændingen. Når kontakten lukker vil kondensatoren hurtigt aflades. Korte hop tilbage til åben position vil oplade kondesatoren lidt mere. Da impedansen til stel er mindre end den til forsyningen vil den hurtigt lande på 0V og blive der når kontakten holder op med at bounce. Forholdet mellem R og C fortæller noget om hvor lang tid de kan kompensere for prel. Bounce kan tage alt fra under 1 ms til 50 ms for relæer – og endnu længere for store kontaktorer. Hvis man designer efter ~5ms er man godt hjulpet med “almindelige” små kontakter. Tau = R*C. Tau er tiden fra 0 til 63% (link). Dimensionerer man efter 3*Tau er man på ~95%. Så hvis man sætter Tau = 5/3ms; R*C=Tau; så får man med en 10K pull up en kondensator på ~2uF. Så – vælg noget i den størrelsesorden.

Bare lige inden jeg får en kæmpe sviner… Kredsløbet ovenfor er i princippet ikke i orden. Hvis man kortslutter kondensatoren med en switch vil der løbe en meget høj strøm gennem switch og kondensator. Det kan kondensatoren ikke holde til i længden – så der burde være en strømbegrænsermodstand i serie med switchen… Nu er du advaret og jeg slipper for tæv :-). I praksis i fuskeropstillinger er det fint og velfungerende.

Inverteren (trekanten med bolle på udgangen) har et “schmitt trigger” symbol. Det betyder at der er tale om en speciel logikkreds der kan fungere korrekt når den udsættes for signaler mellem høj og lav. Normalt er logikkredses logik kun veldefineret når deres input ligger mellem Vil (input low) og Vih (input high):

Det betyder at mellem 0.8 og 2V ved kredsen ikke hvad den skal gøre og det kan give de mest mærkværdige resultater.

En schmitt trigger kreds derimod har en indbygget hysterese. Det betyder at den vil betragte et input som “high” når den passerer “upper threshold”. Det bliver den ved med indtil signalet går under “lower threshold”:

Da vores debounce kredsløb netop benytter sig at at lade det digitale signal være “analogt” i et stykke tid til der er ro på situationen – ja så er en schmitt trigger indgang at foretrække. Arduino (ATmega328) har schmitt triggere på alle inputs – og har i øvrigt synchronizers på også for at sikre meta-stabilitet. Ok – måske en blog om det senere :-).

Der findes et hav af metoder til at løse denne udfordring. Jeg faldt over en helt anden metode som jeg vil beskrive herunder. Så nu – til den lovede lækkerbisken 🙂

Algoritme til rotation og de-bounching

Jeg er lidt høj på en virkeligt smart løsning til at dekode gray code og samtidig eliminere kontaktprel. Jeg faldt over den på nettet mens jeg faktisk ledte efter noget helt andet :-).  Metoden er genial fordi den ikke betragter encoderen som to kontakter og forsøger at debounche dem hver i sær. I stedet udnytter man den egenskaber som gray code har – nemlig at der kun er nogle bestemte kombinationer der er valide. Og det virkelig smukke er at den er utroligt nem at implementere uden at påvirke flowet i koden – og ikke kræver interrupts.

Der er en vigtig antagelse der ligger til grund for denne metodik… Nemlig at der ikke er prel på begge signaler på én gang. Er der bounche på begge kontakter samtidig så er der problemer da vi ikke kan vide hvordan de bouncher i forhold til hinanden. Akslens omdrejningshastighed og hvor lang tid kontakterne bouncher afgør altså om metoden virker.

Artiklen er ikke om specifikt den encoder jeg har – men er helt identisk i funktion – altså mekanisk aflæsning og gray code. Hvis du vil læse originalen (skrevet af Oleg Mazurov) kan du finde den her: link. Jeg skal advare med at sige at der er en fin forklaring – bare ikke på hvorfor det virker… Jeg har prøvet at forklare det lidt dybere herunder.

Grunden til at denne algoritme er så genial er at den kan udføres i sekventiel række uden hensyn til timing og ventetid på at signalerne har stabiliseret sig. Det er en kæmpe fordel når man egentligt bare gerne vil koncentrere sig om funktionaliteten eller ikke vil ofre interrupt-ben og timere på håndteringen.

Men først – hvis du vil lege med har jeg lavet et library som du kan hente her: Download

Lad os starte med at se på hvad vi kan konkludere hvis vi kigger på alle kombinationer af skift i hhv. A og B signalerne. Det er samme betragtning som ovenfor – bare oversat til et univers hvor vi sampler signalerne og detekterer flanker som ændringer fra 0 til 1 og 1 til 0. Jeg benævner for nemheds skyld det nyeste signal for hhv. A og B. De signaler der er målt for “et øjeblik siden” (sidste måling) kalder jeg A’ og B’. Dvs. A’A=00 og =11 betyder uændret og =01 og =10 betyder en hhv. rising og falling flanke.

Invalid / no rotation Clock wise counter clock wise
A’=A; B’=B

(ingen ændringer)

A rise & B low A rise & B high
A’!=A; B’!=B

(begge ændret)

A fall & B high A fall & B low
B rise & A high B rise & A low
B fall & A low B fall & A high

Dvs. rising / falling flank på enten det ene eller andet signal mens det modsatte er stabilt betyder altså rotation. Er signalerne stabile eller ændrede på begge signaler så er der ingen rotation eller signalerne bouncher.

2016-02-04 (3)Gul: rising / falling flanke
Blå: stable position direction
Grøn: med uret
Rød: mod uret
Lys grå: no change
Grå: invalid

Oleg Mazurov oversætter dette diagram til et array hvor index er A’B’AB og outputtet er Q som kan adderes til en tæller for at få den position man har bevæget sig til (-1 er mod uret, 1 er med uret og 0 er invalid/no rotation):

2016-02-04 (3)

static int8_t enc_states[] = {0,-1,1,0,1,0,0,-1,-1,0,0,1,0,1,-1,0};

Index’et (A’B’AB) er indrettet så listigt at det er utroligt nemt at udregne… AB er A og B værdierne som bit 1 og bit 0. Old_AB er en statisk variabel (altså holder sin værdi mellem kald til funktionen):

old_AB <<= 2; //move old AB to A'B'
old_AB |= AB & 0x03; //insert AB as bit 1-0; old_AB is now A'B'AB

Hvis man ikke har AB i samme variabel (det har man ofte kun hvis man læser en port og ikke enkelte pins) så kan man bare skifte linje 2 ud med:

old_AB |= ((A<<1) | (B&0x01))&0x3;

Hvis du er sikker på at der ikke er overflødige 1’ere i  A og B kan du droppe “&0x01” og “&0x03”. De har kun til formål at beskytte mod “støj” i signalerne.

Det eneste der nu mangler er at returnere Q (enc_states i Oleg Mazurov’s terminologi). Det gøres ved at bruge de nederste 4 bit af old_AB (A’B’AB) som index:

return enc_states[ (old_AB & 0x0f) ];

2016-02-07

Meeen – hvorfor virker det egentligt? Hvis B er low og A hopper op og ned – ja så må vi da stadig få fleredetekteringer. Og ja – det gør vi faktisk! Det unikke er at uanset hvor mange “hop” vi når at opdage – så vil den sidste flanke sikre at vi ender på det rigtige. Årsagen er at vi tæller op på hver stigende flanke og ned på den faldende. Da usikkerheden er overstået på måske 5 ms vil det næppe være noget brugeren når at opdage – hvis man eks. bruger det til at styre en menu eller lignende. Hvis man måler på omdrejningshastighed og retning på en motor eller andet hvor det er kritisk, kan man kompensere med elektrisk debouncing som beskrevet ovenfor. Metoden er dog stadig god fordi der kan afvikles i konstant tid (altså tager lige lang tid at udføre hver gang) og fordi der ikke indgår delays eller avancerede timere og interrupts.

Som nævnt skal man bare være sikker på at bounching er ophørt inden man når frem til næste kontakt…

Praktisk med DHV encoderen

Den encoder jeg har er markeret “DHV” og den har tydelig click-markering af step i rotationen. Da ét step giver en flanke på både A og B giver den viste metode 2 step hver gang. For at undgå det har jeg modificeret listen over “lovlige” kombinationer af A’B’AB så ændringer i B ignoreres (ændret til mørkegrå og Q=0):

2016-02-06 (1)

Det betyder at arrayet ændres til:

static int8_t enc_states[] = {0,0,1,0,0,0,0,-1,-1,0,0,0,0,1,0,0};

Og voila – kun ét step per trin på encoderen…




Home automation

Jeg tror enhver nørd drømmer om det store sindsygt smarte og fuldt integrerede home automation system. Med alarm, lysstyring, musik, videoovervågning, ventilation, varme, dørlåse og alt hvad man ellers kan komme i tanke om…

IMG_3585

Og ja – også jeg. Måske mere end de fleste. I 2006 var jeg med en kammerat, Søren, i gang med at udvikle et home automation system der skulle konkurrere med IHC ved at være bedre egnet til renovering af boliger, og ved at være opbygget decentralt så man kunne komme i gang uden at købe en dyr dims til at styre det hele. Vores første enhed skulle være en dobbelt lysdæmper til montering direkte i loftdåser.IMG_3595IMG_3704 Der var den centralt placeret til at modtage “tryk” fra afbrydere (der skulle opgraderes med en fjeder) og havde adgang til lamperne der skulle styres. Mock-up og prototyperne på billederne er af dette modul. Vi designede et ret fedt koncept hvor printene fungerede både som køleflader og stik-forbindelser.
Vi stoppede da det trådløse IHC-system blev introduceret. Bagefter må vi nok erkende at det var lidt heldigt at vi fik stoppet der – med finanskrisen lige om hjørnet kunne vi virkelig have brændt fingrene. Men jeg synes nu stadig at vi havde fat i noget af det rigtige. Især konfiguration af funktionaliteten mener jeg vi havde fat i den lange ende af…

IMG_3594 (2)

Nytårsaften ’15-’16 blev fejret i gode venners lag… Og ja – der går altid nørd i den når Steffen og jeg mødes… Med tiden har emnerne skiftet lidt… Der kommer både lidt teknik og ledelse ind i snakken 🙂

Meeen – Nu er det altså tekniknørderi det gælder.

Steffen har i mange år leget med et home automation system baseret på HomeSeer og X10 baserede enheder. X10 er en protokol der oprindeligt blev udviklet til power line kommunikation (altså kommunikation på 230V nettet) men der er nu også defineret en trådløs variant. HomeSeer er en kommerciel home automation controller. 20160213_101811Controlleren er det lim der binder de forskellige sensorer, relæer, lysdæmpere osv. sammen. Steffen havde fundet ud af at der findes en masse sensorer og udgange (og radiomoduler) som er designet til at blive tilsuttet til en Auduino. OG de kan fås på Ebay og AliExpress til nærmest ingen penge (1-2 USD per dims). Der er et system til at kæde dem trådløst sammen der hedder MySensors. Endelig er der også open source alternativer til HomeSeer (som jeg synes er for pebret).

9d19310763171b0d958d23a18b3d7e1c_400x400Og – så var jeg hooked 🙂

Så jeg brugte nogle timer på ebay i julen. Sørger man for at holde hver ordre under 80 kr incl fragt så er der ingen told og moms på – og det kan man sagtens når der på de fleste dele er med fri fragt og koster 0,5-2 USD per styk.

Arduino

20160213_101918Det første man skal have styr på er selve Arduino’en. Der findes et hav af forskellige modeller. Jeg har valgt at fokusere på Arduino Uno og Arduino Nano – begge baseret på Atmel ATmega328 microprocessoren. Uno er fysisk større og har USB-stik on-board og er derfor fin til test og udvikling. Nano er fin til de sensorer der bygges, da den er mindre og kan klemmes ind hvor de nu skal bruges.

ArduinoUno_R3_Pinouts_600Arduino er et “format” som reelt bare dækker over en Atmel ATmega processer hvor det grundlæggende (oscillator og forsyning) ligger på boardet og alle pins er ført ud til pinheaders så det er nemt at slutte andre enheder til.
Da placeringen af headerne er standardiseret findes der et hav af “shields” – altså print der bare skal presses ned over moder-printet som giver alverdens funktioner: Display, ekstra hukommelse, real time clock, fugt/tenmperatur sensor og 100 andre.

Atmel laver en meget stor familie af nogle ret gode og billige processorer. De starter i ATtiny til et par kroner og op til ATmega til 120 kr. Ved Digikey koster en ATmega328 ca. 8 kr. Hvordan kineserne på ebay så er i stand til at lave en Arduino Uno til ca. 22 kr og en Nano til 10 kr er mig absolut en gåde…

genuinobrandStifterne bag Arduino røg for nogle år siden i totterne på hinanden. Det var noget med at de hver især mente at eje domæne og registrerede varemærker. Så i dag kan Arduino også købes under navnet Genuino…

Arduino modellerne begge baseret på den samme microcontroller (ATmega328) – så de har de samme ben og funktioner. Mange ben kan bruges til flere ting så man har både interrupt inputs, analoge inputs, pwm outputs, capture inputs (kobles til timere) og sikkert mere jeg ikke lige kan komme i tanke om. Der er 15 digitale pins samt 6 analoge inputs der også kan bruges som digitale ind-/udgange. En lidt spøjs ting er at Arduino’s benævnelse af benene. Det er lidt forvirrende at de ikke bruger de samme betegnelser som Atmel. Port D (altså D0-7) svarer til ben 0-7 på Arduino. Port B (B0-5) svarer til ben 8-13 på Arduino. Port C (C0-5) svarer til A0-5 på Arduino.

Micro’en har 2KB ram (der glemmer ved power off), 1KB eeprom (der kan huske også selvom strømmen afbrydes og som er nem at skrive til i applikationen) og 32 KB flash (kode memory). Den kører med en 16MHz clock.

Mega2-900Arduino giver faktisk ret meget for pengene. Og kan man ikke være i formatet kan man skifte til Arduino Mega2560 der er baseret på ATmega2560. Den har  16 analoge inputs og 54 digitale i/o. Det kan man hurtigt få lyst til hvis man begynder at sætte display, 2-3 temperatursensorer, relæudgange og andet sjov på samme controller…

Udviklingsmiljø (IDE)

Der er forskellige udviklingsmiljøer til arduino. Dels de originale fra Arduino som kan hentes på arduino.cc (link) og dels et online miljø på codebender.cc (link). Jeg har leget med begge dele – og havde jævnt mange problemer med codebender.cc. Men Steffen bruger det så det må kunne bringes til at makke ret… Det fede ved codebender er at der er utroligt nem adgang til alle de andre udvikleres kode og der er et hav af officielle libraries. Jeg har på grund af problemerne valgt miljøet fra arduino.cc. Det skal dog ikke hindre mig i at stjæle med arme og ben fra det kode der ligger på codebender…

2016-02-13Uanset hviket miljø man vælger er der utroligt mange ting der bare virker “out of the box”. Ting man som traditionel udvikler selv må klare – såsom biblioteker med adgang til hardwaren og håndtering af interrupts etc. Alt det og meget mere er der taget hånd om – men som gammel embedded udvikler kræver det altså lidt tilvænning ikke at have indflydelse på alting 🙂

Et første forsøg…

Jeg vil rigtigt gerne lægge links til ebay her… Meeen – ebay linkene har en tendens til at gå tabt kort efter kort tid. Så i stedet vil jeg skrive de nøgleord som man kan bruge til at søge stumperne efter. 2016-02-07 (1)Et lille tip til brug af ebay… Hvis du vælger “Lowest price + P&P” så får du alle dem med gratis fragt 🙂 først i listen.

Stumperne i dette indlæg er: “arduino nano 328 5v”; “arduino ft232rl usb to serial adaptor”; “arduino led breakout board”; “Male To Female Jumper Wire”; “Male To Female Jumper Wire”.

Efter jeg modtog de første stumper skulle den første prøve stå…

2016-02-07 (2)Nano har ikke indbygget USB-adaptor – så det første var at slutte USB-serial port til. Det var ret nemt 🙂 – 6 ben lige igennem. Det er her “female to female jumper cables” kommer i brug. Det er en dejligt nem måde at klaske ting sammen på. Ikke egnet til den endelige applikation men fin til test.

Step to var at forbinde lysdioderne. De har et stelben og 6 lysdiodeben. Det passer så fikst at de kan sættes på GND og ben 2-7 der ligger lige ved siden af hinanden.20160211_212708

Mit første eksempel fandt jeg på codebender – en simpel LED blink test. Jeg modificerede den lidt så den laver et løbelys på det eksterne lysdiodepanel 🙂

Hent eksemplet her: Invalid download ID.

Voila – oppe at køre… 🙂




Logic analyzer – Low cost…!

20160210_212621Jeg stod for nylig med en udfordring  – en af mine arduino sensorer holdt op med at virke når jeg kommunikerede med den for hurtigt… Min eneste indsigt i kommunikationen var gennem det softwaren gav – og det bragte mig ikke videre… Interfacet er via SPI som jeg bit-banger – dvs. styrer manuelt i stedet for at bruge den indbyggede SPI-controller i ATmega microcontrolleren.

Havde jeg ikke været for doven ville jeg være gået i kælderen, havde sat oscilloscopet på og analyseret signalerne på ledningerne. Desværre har jeg kun et 2-kanals scope og det har ingen SPI dekodning indbygget – så det ville være møg bøvlet på godt jysk…

Det “rigtige” værktøj til en applikation som denne er en logik analysator. Det er et digitalt oscilloscope – altså i stedet for at kunne måle analoge spændinger så måler den kun “1” og “0”. Det kan gøres meget billigere og de fleste logikanalysatorer har ret mange inputs (kanaler). De fleste har desuden avanceret dekodning af signaler – eks. SPI som jeg godt kunne bruge her…

Geeetech_1CY7C68013ASå – jeg gik på jagt med den intention at finde noget der ikke koster en million. Det naturlige var at kigge efter en USB-dims så jeg ikke skulle betale for en skærm – når den på PC’en sådan set virker fint. Det kunne også spare på bordpladsen 🙂

Med min nylige succes / overforbrug på ebay søgte jeg der – og efter nogen søgen opdagede jeg nogle moduler baseret på en Cypres CY7C68013A-56 chip.

til GPB 3,5 virkede det ret attraktivt… Jeg søgte dog efter software til den – og det vist sig at være ret tricky – noget med at downloade nogle developer tools fra Cypres’ hjemmeside. Lød lidt for bøvlet til mit temperament :-).

20160210_211531Så jeg ledte videre og endte på en “Hobby Components 8 ch / 24 MHZ logic analyzer”. Det er et britisk firma der har taget et af cypress modulerne og lagt deres egen firmware i – og så bruger det et open source tool der hedder “Sigrock Pulseview” (link) til analyen på pc. Det tændte jeg på – også selvom prisen var hele £9.90.

2016-02-10 (2)Da jeg fik den opstod der ca. en halv times total forvirring om drivere. Pulseview ville ikke genkende min logikanalysator… Det viste sig at Hobby Components har lavet en opdatering i efteråret og forvirringen skyltes dels at jeg ikke vidste hvilken version jeg havde og dels at jeg ikke tænkte på at tage USB-stikket ud og ind og genstarte Pulseview flere gange. Så – hermed viderebragt 🙂

Sigrok Pulseview

Programmet er open source og der er ingen releases (i hvert fald ikke til Windows) – så man henter bare det seneste nightly build… (link)

Når altså driveren først er installeret opdager Pulseview selv logikanalysatoren og tilbyder de 8 kanaler med det samme. Konceptet er ret enkelt.2016-02-10 (1)

I det store areal vises de digitale kanaler. På “bobbel-knappen” kan man tilføje “logiske” kanaler som er dekodede / fortolkede versioner af de primære logiksignaler. Det er ret nemt at tilføje kanaler og så konfigurere hvilke ben der anvendes til hvad. Man kan tilføje flere samtidig.2016-02-10 (4)

En af de vigtigste ting ved en logikanalysator er at kunne indstille hvor hurtigt / længe der skal samples OG hvornår sampling skal starte… 2016-02-10 (1)Samplerate og antal samples indstilles i menuen. Helt enkelt samples/sec (Hz) og antal samples. 2016-02-10 (5)Tiden bliver så samplerate * samples… “Run” knappen sætter det hele i gang. Hvis man ikke gør andet starter sampling med det samme – men man kan også definere triggere. Det gøres ved at clicke på et signal og definere hvilke flanker der skal fungere som triggere.

Et praktisk eksempel

Nu hvor det virker – så lad os lave et praktisk eksempel.

Jeg skriver på et blogindlæg om en quadrature encoder til Arduino. Det er en mekanisk encoder som med to ben giver mulighed for at regne ud hvor akslen står.

Jeg vil gerne se om jeg misser step når jeg drejer så hurtigt som jeg kan. Og… om der er kontaktprel…

Så jeg modificerer koden til at sende de nederste 4 bit af positionen ud på port D (Arduino pin 8-11). Dem tilslutter jeg på logikanalysatoren ben 1, 3, 5, 7. Ben 4, 6 bliver til A og B på quadrature encoderen.

Jeg brugte “skruetrækkeren” i menuen til at fjerne pin 1, 3, 5, 7 som jeg dekoder i en paralle dekoder. Og så konfigurerede jeg en trigger på A:

2016-02-10

Som det kan ses tæller den rigtigt :-). Der er en tælling for hver flanke

For at se reaktionen ved max hastighed satte jeg sample rate op til 6 MHz og vred akslen så hurtigt som muligt. Og… som forventet kunne koden ikke nå at fange dem alle som det kan ses her:2016-02-10 (6)

Som det kan ses står tælleren stille på 5 mens signalerne på A og B skifter flere gange. Kan den følge med vil der være ny tællerværdi for hvert skift i enten A eller B. Den blå markering er fra en cursor jeg satte på for at se hvilken tidsramme vi er i. Og det blå område er 18ms bredt. Det sjove er at 2 og 3 er meget korte / hurtige mens 4 og 5 er langsomme. Mit umiddelbare gæt er at koden går i gang med at sende serielle signaler ud på konsollen – men det har jeg nu indsigt nok til at kunne arbejde med.

Det er denne type indsigt som en logikanalysator kan give. Selvfølgelig havde det været fedt med en der også lige havde 4 analoge kanaler 🙂 – men til prisen (~100 kr incl. fragt) er dette her faktisk helt fantastisk!

Nå – og nu må jeg hellere få fundet den fejl jeg startede bloggen
med 🙂