Programmering for begyndere Brug af Arduino Programmeringskursus Analoge indgange og A/D konvertering Analoge udgange Knud Krogsgaard Jensen OZ1QK
Oversigt Oversigt over i aften: A/D konvertering iterations processen Sampling og hold processen (lidt kort) Program som bruge analog input. Metoder til støjreduktion (stop processor) Analoge udgange Hvad skal vi med de to sidste gange? Hvad sker der efter nytår?
A/D konvertering End of Convertion Princip SAR Successiv approksimations register DAC Digital til analog konverter S/H Sample and hold
A/D konvertering Sample and hold Det er måske ikke vigtig lige nu. (Jeg vender tilbage til det senere.) Det er dog nok godt, at huske at det er øjeblikværdien man måler må. Kontakten er sluttet et øjeblik og det er den værdi man måler på.
A/D konvertering Selve A/D konverteringen Lad os sige at signalet vi ønsker at konvertere er mellem 0V og 5V. I Arduino (Atmega328P) har vi en 10-bit A/D konverter. Det vil sige vi har fra 00 0000 0000 11 1111 1111 eller fra 000 3FF(HEX). eller fra 0 1024 (DEC Naturlige er at 0 Volt 5 Volt Opgaven er hvordan får vi hurtige bestemt hvilken digital værdi der passer til en given spænding.
A/D konvertering Et par betegnelser: Jeg her lige brug for et par begtegnelser MSB = Most Significant Bit / Mest betydende bit LSB = Least Significant bit / Mindst betydende bit Hvis vi har den binære kode 10 0000 1011 MSB LSB
A/D konvertering Successiv approksimation Vi starter med at sætte MSB = 1, dvs. den halve spænding. 5000 mv x mv Første forsøg 10 0000 0000(BIN) = 200(HEX) = 256(DEC) (= 2500 mv) 0 mv
A/D konvertering Successiv approksimation Det var ikke nok. Så sætter vi den også næst betydende bit = 1 x mv 5000 mv Andet forsøg 11 0000 0000(BIN) = 300(HEX) = 768(DEC) (= 3500 mv) 0 mv
A/D konvertering Successiv approksimation Hvis spænding havde været lavere skulle vi sætte MSB = 0 og den næst betydende bit = 1: 5000 mv y mv Andet forsøg 01 0000 0000(BIN) = 100(HEX) (= 1250 mv) 0 mv
A/D konvertering Successiv approksimation Vi prøver altså at sætte et bit højt begyndende med det mest betydende bit og se om det går godt. Det er godt at vide; men det er der jo taget hånd om i Arduino (Atmega328P). Resultatet er at den A/D omsætning sker på 13 270 usek. (Det vender vi lige tilbage til det har noget at gøre med hvor hurtigt varierende signaler vi kan arbejde med.) Først noget med opløsning.
A/D konvertering A/D konverterens opløsning. Vi har 10 bit dvs. 1024 tilstande. Vi lader 11 1111 1111 = 3F svarer til 5000 mv Vi lader 00 0000 0000 = 00 svarer til 0 mv Hvor mange mv svarer hvert trin så til??
A/D konvertering A/D konverterens opløsning. Vi begynder lidt simplere: Antag vi har en 2 bit A/Dkonverter: Man kan også vise det således: Volt 5 Her er altså 3 trin 00 0 Volt 01?? 10?? 11 5 Volt 0 00 01 10 11
A/D konvertering For 2- bit konverteren gælder altså: Med reference spænding 5000 mv er hvert trin: 5000 mv / 3 trin = 1666,7 mv / trin Det vil sige har vi har: 00 0 0 mv 01 1 1667 mv 10 2 3333 mv 11 3 5000 mv 13
A/D konvertering For 10 - bit konverteren gælder: Antal tilstande: 2 10 = 1024 tilstand. Det vil sige at der er 1023 trin 5000 mv / 1023 trin = 4,888 mv / trin Mange steder anvendes 1024. Det finder man i datablade og mange andre steder. Ind til videre mener jeg, at 1023 er det rigtige tal. Fejlen er ofte helt ubetydelig 0,98. Ofte mindre end andre fejlkilder. 14
A/D konvertering For 10 - bit konverteren gælder: Spændingen på indgangen beregnes ved: Hvis vi fra A/D konverter udlæser tallet A kan spændingen dette skare til beregnes ved: Vmålt = Vref * A / 1023 = 5000mV * A / 1023 = 4,888 mv *A 15
A/D konvertering Fejlkilder Nøjagtighed af reference spændingen Nulpunktsfejl Forstærkningsfejl Ikke lineær konvertering (trappen er ikke jævn) Det vil jeg ikke gøre noget ud af nu. Der står en del om det i databladet for processoren. (Det meste er i småtingsafdelingen) Nu må det være tid til at se hvordan det gøres med Arduino og et C-program
A/D konvertering med Arduino Programmeringskursus Arduino (Atmega328P) (Jeg ved godt at man intet kan se) Separat strømforsyning til S/H kredsløb Reference spænding Analoge indgange D/Akonverter
A/D konvertering med Arduino Programmeringskursus Opstilling:
A/D konvertering med Arduino Programmeringskursus Program der aflæser A/D indgang og sender det til et display /* Simpel udlæsning fra AD-konverter*/ #include <LiquidCrystal.h> long raadata; long volt; int adinputpin = A0; // Ben for analog input LiquidCrystal lcd(12,11, 5, 4, 3, 2); void loop() { raadata = analogread(adinputpin); lcd.setcursor(11,2); lcd.print(raadata); delay(1000) } Lavet med kode som ikke er vist void setup() { lcd.begin(20, 4); lcd.clear(); lcd.setcursor(0,2); lcd.print("raadata :"); } U d l a e s n i n g f r a A / D - k o n v e r t e r R a a d a t a : 1 6 1 Position (11,2)
A/D konvertering med Arduino Programmeringskursus Program der aflæser A/D indgang og konverterer til Volt /* Simpel udlæsning fra AD-konverter*/ #include <LiquidCrystal.h> long raadata; long volt; int adinputpin = A0; // Ben for analog input LiquidCrystal lcd(12,11, 5, 4, 3, 2); void setup() { lcd.begin(20, 4); lcd.clear(); lcd.setcursor(0,2); lcd.print("raadata :"); lcd.setcursor(0,3); lcd.print("spandenig:"); } void loop() { raadata = analogread(adinputpin); volt = raadata * 5000 / 1023; lcd.setcursor(11,2); lcd.print(raadata); lcd.setcursor(11,3); lcd.print(volt); delay(1000); } U d l a e s n i n g f r a A / D - k o n v e r t e r R a a d a t a : 1 6 1 S p a n d e n i g : 7 8 7 Lavet med kode som ikke er vist
A/D konvertering med Arduino Programmeringskursus Kommentar Variablerne raadata og volt er long fordi det ikke er muligt int. Brug af int giver overflow: Vi har jo at 0 raadata 1024. Da int max er 32.767 så bliver raadata * 5000 meget let for stor. Det går med long thi intervallet er -2.147483.648 +2.147.483.647.
A/D konvertering med Arduino Programmeringskursus Omregning af rådata Vi brugte jo en formel til omregning af de data vi hentede fra A/D-omsættern til volt. map() er et hjælpemiddel hvis man ikke kan lide formeler: resultat = map(value, fromlow, fromhigh, tolow, tohigh) Resultat Værdi som skal konverteres Nedre værdi for value Øvre værdi for value Nedre værdi for resultat Øvre værdi for resultat
A/D konvertering med Arduino Programmeringskursus Eksempler på brug af map() Vores eksempel fra før bliver: volt = map(raadata, 0, 1024, 0, 5000);
A/D konvertering med Arduino Programmeringskursus Eksempler på brug af map() Vores eksempel fra før bliver: volt = map(raadata, 0, 1024, 0, 5000); map() kan også vende rundt på inddata: volt = map(raadata, 0, 1024, 5000, 0);
A/D konvertering med Arduino Programmeringskursus Eksempler på brug af map() Vores eksempel fra før bliver: volt = map(raadata, 0, 1024, 0, 5000); map() kan også vende rundt på inddata: volt = map(raadata, 0, 1024, 5000, 0); map() kan også arbejde med negative tal: resultat = map(raadata, 1, 50, 50, -100); Det giver problemer hvis grænserne for inddata går uden for grænserne. Brug evt. constrain()
A/D konvertering med Arduino Programmeringskursus Antennerotor En antennerotor styret fra et potentiometer kunne omregningen til grader se således ud: grader = map(raadata, 0, 1024, 0, 360);
A/D konvertering med Arduino Programmeringskursus Program der aflæser A/D indgang og konverterer til Volt Brug af map() /* Simpel udlæsning fra AD-konverter*/ #include <LiquidCrystal.h> long raadata; long volt; int adinputpin = A0; // Ben for analog input LiquidCrystal lcd(12,11, 5, 4, 3, 2); void setup() { lcd.begin(20, 4); lcd.clear(); lcd.setcursor(0,2); lcd.print("raadata :"); lcd.setcursor(0,3); lcd.print("spandenig:"); } void loop() { raadata = analogread(adinputpin); volt = map(raadata,0,1024,0,5000); lcd.setcursor(11,2); lcd.print(raadata); lcd.setcursor(11,3); lcd.print(volt); delay(1000); } U d l a e s n i n g f r a A / D - k o n v e r t e r R a a d a t a : 1 6 1 S p a n d e n i g : 7 8 7 Lavet med kode som ikke er vist
A/D konvertering med Arduino Programmeringskursus Et par bemærkninger Output fra A/D-konverteren vil aldrig nå 3FF; men højest 3FE = 11 1111 1110. Det er en følge af den måde konverteringen sker på. Det er ikke rigtigt noget der har betydning. Ved 5V reference er det 5000 mv 4,8888 mv = 4995,1 mv. Der er mulighed for at bruge en intern reference på 1,1 V. Hvis man har et indgangssignal, som ikke kan nå 5 V skal man bruge en reference der er mindre end 5 V, da 1023 (3FF) altid vil svare til referencespændingen. Indgangsspændingen må ikke overstige 5 V. Brug spændingsdeler.
A/D konvertering og stepmotor Programmeringskursus void loop() { //rettet til til brug på OH raadata =analogread(adinputpin); grader = map(raadata,0,1024,20,540); lcd.setcursor(0,3); lcd.print("koerer nu frem "); lcd.setcursor(0,1); lcd.print(" "); lcd.setcursor(0,1); lcd.print (grader,0); RunMotor(8*grader); lcd.setcursor(0,3); lcd.print("er i yderpossition "); delay(5000); } lcd.setcursor(0,3); lcd.print("koerer nu baglens "); RunMotor(-8*grader); lcd.setcursor(0,3); lcd.print("er tilbage ved start "); delay(5000);
A/D konvertering og stepmotor Programmeringskursus void RunMotor(int trin) { int stepdelay = 1000 / speed; if (trin > 0) digitalwrite(dirpin, HIGH); //frem else { digitalwrite(dirpin, LOW); // bak trin = -trin; } while(trin l > 0) { digitalwrite(steppin,high); delaymicroseconds(1); digitalwrite(steppin,low); delay(stepdelay); trin = trin -1; if ((trin % 25) == 0) { //udskriver hver 25. lcd.setcursor(0,2); lcd.print(" "); lcd.setcursor(0,2); lcd.print(trin); } } }
A/D konvertering med Arduino Sampling Programmeringskursus I har formentlig hørt om det med samplingsteori. Kort og godt handler det om at man ikke uden videre kan nøjes med at kikke Det er det med at hvis man vil måle et signal et ac-signal så skal man måle med den dobbelte frekvens. Jeg vil ikke gå ret meget ind i dette fordi det primært er et programmeringskursus.
A/D konvertering med Arduino Sampling Programmeringskursus Jeg har ikke været dybt nede i hvorledes programmet i Arduino er lavet. Hvis en hver A/D konvertering svaret til en first conversion, så tager det 12,5 cycles til Sampel & Hold 24 cycles til konvertering 36,5 cycles á 62,5 ns 428 A/D konverteringer / sek Hvis det holder stik så kan vi højest behandle signaler op til ca 200 Hz. Ellers skal vi over i maskinkode.
A/D konvertering med Arduino Programmeringskursus Støjreduktion Det er begrænset hvad vi kan gøre fordi print layout er fast. Processoren (ATmega328) kan stoppes under AD konverteringen Jeg har ikke fundet funktioner der kan gøre dette i instruktionssættet fra C. De analoge ben kan bruges som udgange hvis man har behov for det. Man må tage særlige hensyn hvis man derefter begynder at brug dem som indgange.
Analoge udgange fra Arduino Programmeringskursus
Analoge udgange på Arduino Analog udgange En mulighed for at få et analog signal ud af Arduino. I virkeligheden er det et pulsmoduleret signal med en frekvens på 490 Hz. Det kan lade sig gøre på ben 3, 5, 6, 9, 10, og 11. Det er dem der er markeret med.ԝݟԝ.ԝݟԝ. Funktionen er : analogwrite(ben, tal); hvor 0 tal 255
Analoge udgange på Arduino Pulsmodduleret signal: 0 % duty cycle, analogwrite (0) 25 % duty cycle, anlaog Write(64) 50 % duty cycle, analogwrite(127) 75 % duty cycle, analogwrite(191) 100 % duty cycle, analogwrite(255)
Analoge udgange på Arduino Her er et program vi har set før med et par tilføjelser /* Simpel udlæsning fra AD-konverter*/ #include <LiquidCrystal.h> long raadata; long volt; int adinputpin = A0; // Ben for analog input int LedBen = 9; LiquidCrystal lcd(12,11, 5, 4, 3, 2); void setup() { lcd.begin(20, 4); lcd.clear(); lcd.setcursor(0,2); lcd.print("raadata :"); lcd.setcursor(0,3); lcd.print("spandenig:"); } Lavet med kode som void loop() { ikke er vist raadata = analogread(adinputpin); volt = map(raadata,0,1024,0,5000); analogwrite(ledben, raadata / 4 ); lcd.setcursor(11,2); lcd.print(raadata); lcd.setcursor(11,3); lcd.print(volt); delay(1000); } U d l a e s n i n g f r a A / D - k o n v e r t e r R a a d a t a : 1 6 1 S p a n d e n i g : 7 8 7
A/D konvertering og stepmotor Programmeringskursus Her er et andet program vi har set før: void RunMotor(int trin) { int stepdelay = 1000 / speed; if (trin > 0) digitalwrite(dirpin, HIGH); //frem else { digitalwrite(dirpin, LOW); // bak trin = -trin; } l while(trin > 0) { digitalwrite(steppin,high); delaymicroseconds(1); digitalwrite(steppin,low); delay(stepdelay); analogwrite(ledpin, trin % 225); trin = trin -1; if ((trin % 25) == 0) { //udskriver hver 25. lcd.setcursor(0,2); lcd.print(" "); lcd.setcursor(0,2); lcd.print(trin); } } }
Programmering af Arduino Det var stoffet for i aften Hvad nu??? I slipper ikke - Nu er det jer der skal på senen
Hvad nu? Vi har to kursusaftener tilbage: Mandag den 3. december A/D konvertering (her må vi nok finde på noget andet!) mandag den 10. december Afslutning Hvad gør vi næste år?? Vi tager lige en ting af gangen!
De to sidste kursusgange Programmeringskursus Her er nogle forslag til de sidste to gange: Interrupt Timer funktionen Pointere I 2 C Løse nogle opgaver (undere vejledning) Det uddybes her
De to sidste kursusgange Programmeringskursus Uddybning Interrupt Mulighed for at afbryde en opgave for at foretage sig noget der er vigtigere, og så vende tilbage til den opgave der blev afbrudt. Timer funktionen Muligheden for at afbryde en opgave, efter et bestemte tidsrum. Det kan være der data er tilrådighed som skal sendes, eller en information der skal sendes. Pointere Pegepinde som kan bruges til at pege på data. Bruges bl.a. til at lade funktioner ændre mere end en enkel variabel. I 2 C En protokol til at kommunikerer med enheder uden for Arduino ved hjælp at to ben. Display, flere knapper på forplade.... Løse opgaver Man lærer kun ved at gøre det; men mon 2 * 2 timer gør en forskel?
De to sidste kursusgange Programmeringskursus Mit forslag: Interrupt Timer funktionen De to sidste gange Det er et forslag, der giver mig en del arbejde Pointere I 2 C. Løse opgaver Dele af forårets arbejde Jeres forslag udbedes nu!
Forslag til programmerings aktiviteter næste år
Hvad gør vi næste år?? Forudsætninger for aktiviteter: Helt på egen regning Hvis vi skal lære at bruge programmering som værktøj så skal der iværksættes aktiviteter. Hvis man vil noget med det man gør skal der være et mål! Et godt mål skal opfylde følgende: Det skal være realistisk Det skal være udfordrende Man skal kunne afgøre at målet er nået Et hvert skridt mod målet skal bidrage til noget positivt Det vi iværksætter skal være noget vi hver især har lyst til
Hvad gør vi næste år?? Hvad vi IKKE skal: Lade som ingen ting og tro på, at også dem, der ikke har programmeret før, bruger programmering som værktøj Lave et kursusforløb hvor vi lokker en til at præsentere noget mere om programmering. (Har vanskeligt ved at se hvad man meningsfyld skal tale om.)
Hvad gør vi næste år?? Hvad er det egentlig vi har? Vi har nu samlet nogle radioamatører som gerne vil programmerer. Vi er i gang med at opbygge et miljø for programmering Det synes jeg vi skal udbygge og holde fast i.
Hvad gør vi næste år?? Mulige aktiviteter Lave et programmerings projekt Lave hver vort programmerings projekt Lave åben workshop hver tredje mandag...... Forslag til projekter Kommentarer - forslag
Hvad gør vi næste år?? Udfordringen er: at lave hver vort programmerings projekt og samtidig holde sammen på os gøre en åben workshop hver tredje mandag(?) meningsfyldt Kan måske samlet i et projekt ved Brug af I 2 C til kommunikation mellem Arduino og Display Tastatur / nogle knapper Stepmotor VFO... Dit forslag