www.elektronik.si Seznam forumov www.elektronik.si
Forum o elektrotehniki in računalništvu
 
 PomočPomoč  IščiIšči  Seznam članovSeznam članov  SkupineSkupine  StatisticsStatistika  AlbumAlbum  DatotekeFilemanager DokumentacijaDocDB LinksPovezave   Registriraj seRegistriraj se 
  PravilaPravila  LinksBolha  PriponkePriponke  KoledarKoledar  ZapiskiZapiski Tvoj profilTvoj profil Prijava za pregled zasebnih sporočilPrijava za pregled zasebnih sporočil PrijavaPrijava 

Prvi koraki z LPC1343 & Keil - povzetek predavanj
Pojdi na stran 1, 2  Naslednja
 
Objavi novo temo   Odgovori na to temo   Printer-friendly version    www.elektronik.si Seznam forumov -> ARM arhitektura
Poglej prejšnjo temo :: Poglej naslednjo temo  
Avtor Sporočilo
Highlag
Član
Član



Pridružen-a: Pet 23 Jan 2004 20:42
Prispevkov: 4034
Aktiv.: 18.17
Kraj: Črnuče

PrispevekObjavljeno: Čet Jul 12, 2012 10:23 pm    Naslov sporočila: icon_idea Prvi koraki z LPC1343 & Keil - povzetek predavanj Odgovori s citatom

Prvi koraki pri uporabi C programskega jezika, razvojnega okolja Keil microvision, ter LPC 1343F procesorja.
Za prve korake bomo potrebovali:

    - Razvojno okolje Keil microvision, ki se lahko dobi tule: https://www.keil.com/demo/eval/arm.htm
    - Demo verzija ima sicer omejitve, kot so količina prevedene kode, manjka optimizacija in še nekaj drugih podrobnosti, ki pa na delo z LPC1343 nebi smeli vplivati. Namestitev programa se privzeto izvrši v mapo C:\Keil. V nasprotnem primeru bi bilo potrebno nastaviti kakšno stvar drugače, kot je opisano v tem postopku.
    - Procesor je prispajkan na TIV uLPC1000, ki je na voljo preko www.poscope.com - brez procesorja! Na voljo je tudi PDF z električno shemo ploščice.
    - Za prikop ploščice potrebujemo tudi USB kabel USB A na B.


Procesor LPC1343 vsebuje usb bootloader, ki omogoča, da se procesor računalniku predstavi kot USB ključek.

Postopek nalaganja programa na procesor:

    - Ob priklopu TIV uLPC1000 s procesorjem na USB računalnika se na TIV prižge LED power, v procesorju se prične izvajati vpisan program.
    - Pritisnemo tipko INT, nato pa še RESET.
    - Prižge se LED USC.
    - Na računalniku se pojavi nov disk CRP DISABLED, ki vsebuje eno datoteko firmware.bin
    - Datoteka firmware.bin je vedno enake dolžine - ustreza prostoru, ki ga ima procesor na razpolago za program (32KB za LPC1343) prav tako ima vedno enako ime.
    - Če hočemo na procesor naložiti nov program moramo datoteko prej pobrisati.
    - Nalaganje novega programa obsega kopiranje prevedenega programa (bin datoteke) na naš najljubši način na disk CRP DISABLED.
    - Ko je program naložen je potrebno procesor s pritiskom na tipko RESET resetirati in procesor ob zagonu ponovno prične z izvajanjem naloženega programa
    - Ob prvem priklopu ploščice s procesorjem morajo okna najprej naložiti gonilnike.


Postopek izdelave novega projekta v delovnem okolju Keil uVision:

    - New uVision project. Izberemo mapo projekta, vpišemo ime projekta. Na primer Ime_projekta
    - Nato izberemo procesor, ki ga bomo uporabljali v našem primeru gre za : NXP/LPC1343, in v oknu, ki se odpre izberemo OK.
    - Prikaže se delovno okolje.
    - V levem oknu (Project) imamo 2 mapi. Mapo Target 1 in podmapo Source Group 1. V zadnji imamo datoteko startup_LPC13xx.s.
    - Imena map lahko zamenjamo tako, da kliknemo na meni Project/Manage/Components Environment Books.
    - Odpre se okno.
    - Izberemo mapo, katere ime nas moti, pritisnemo F2 in vpišemo novo ime.
    - Mape lahko poljubno urejamo – dodamo lahko nove ali jih brišemo ter vanje dodajamo datoteke. Vse z namenom, da je preglednost projekta boljša.
    - V urejevalnem oknu kliknemo na mapo Source group 1 in kliknemo na gumb Add files.
    - Odpre se okno za izbiro datoteke. Najti moramo tole: C:\Keil\ARM\Boards\Keil\MCB1000\MCB1313\Blinky\system_LPC13xx.c
    - Izberemo in potrdimo, nato pa kliknemo gumb OK. Okno se zapre in v mapi Source group 1 se pojavi datoteka system_LPC13xx.c.
    - Sedaj lahko po podobnem postopku dodamo še mapo Source code v katero lahko shranimo svojo datoteko C. To storimo tako, da kliknemo na File/New izberemo ime in končnico svoje datoteke na primer Ckoda.c. Shranimo. V datoteko napišemo svoj program. Za začetek recimo tole:


Koda:
#include <stdio.h>
#include "LPC13xx.h"

int main (void) {

while (1) {}

}


    - Tako, da imamo nekaj kar se lahko prevede.
    - Napisano pa se trenutno še ne prevede uspešno.
    - Našo kodo je najprej potrebno dodati k projektu. To storimo na enak način kot smo prej dodali datoteko system_LPC13xx.c.
    - Nastaviti moramo še orodja, ki so potrebna za prevajanje kode v bin format.
    - V mapo C:\Keil\ARM\BIN40 moramo prekopirati programček lpcrc.exe, da bo imela prevedena bin datoteka ustrezen CRC.
    - To storimo v meniju Flash tools. Kliknemo na Flash/Configure flash tools Odpre se okno.
      - V zavihku Target nastavimo frekvenco kristala, ki se nahaja na tiskanem vezju – v našem primeru 12MHz
      - V zavihku Output nastavimo naslednje:
      - Select folder for objects: Izber mapo v katero bi rad hranil prevedeno kodo: Mi smo imeli nastavljeno na Flash v podmapi projekta. V polje Name of Executable vpiši želeno ime datoteke. Recimo Projekt.
      - V zavihek User nastavi naslednje:
      - Run user programs ater build/rebuild:
      - Run #1: C:\Keil\ARM\BIN40\fromelf.exe --bin --output Flash\Projekt.bin Flash\Projekt.axf, pri cemer je Flash mapa ki je bila nastavljena v zavihku Output Projekt.axf pa ime datoteke, ki je bilo nastavljeno v zavihku Output
      - Run #2: C:\Keil\ARM\BIN40\lpcrc.exe Flash\Projekt.bin, pri cemer je Flash mapa ki je bila nastavljena v zavihku Output Projekt.bin pa ime datoteke, ki je bilo nastavljeno v zavihku Output
      - Potrdimo z OK

    - Projekt se sedaj uspešno prevede.

    - Ko je projekt uspešno preveden se v mapi Flash pojavi en kup datotek, med njimi pa je ena z imenom Projekt.bin, ki se jo lahko prekopira na procesor.


C in LPC1343

Tule ne bo detajlnega opisa C jezika in njegove strukture, le nekaj najosnovnejših ukazov in delov, ki so direktno vezani na uporabo C jezika pri programiranju LPC1343.

Pri pisanju programov je pametno svoje delo komentirati. To se lahko stori na dva načina:
Z uporabo znakov "//" - besedilo za znakoma // je komentar, ki se razteza samo čez eno vrstico programske kode.
Z uporabo para "/* */" - besedilo med znaki /* */ je komentar, ki se lahko razteza čez več vrstic programske kode.

Pri uporabi procesorja - predvsem pri pisanju programov se je potrebno s procesorjem kar intimno spoznati. Pisanje programov je drugače skoraj nemogoče, če ne poznamo ukazov s katerimi procesor prepričamo, da ob želenemu času ustrezno vključi ali izključi izhode in s tem opravi določeno nalogo.

Najosnovnejše operacije, ki jih mora procesor opravljati so prejemanje in pošiljanje podatkov preko svojih nožic v zunanji svet. Da je stvar bolj zamotana lahko posamezna nožica procesorja opravlja več funkcij. Da ustrezno deluje je potrebno procesor ustrezno nastaviti.

Procesor LPC 1343 ima 48 nožic.
Razporejene pa so v 4 splošne vhodno-izhodne (I/O)enote, ki se imenujejo PIO0, PIO1, PIO2, PIO3 in nekaj drugih delov. Posamezne
    I/O enote imajo različno število nožic:
    PIO0 ima na razpolago 12 nožic označenih od 0-11: POI0_0 do PIO0_11.
    PIO1 ima na razpolago 12 nožic označenih od 0-11: POI1_0 do PIO1_11.
    PIO2 ima na razpolago 12 nožic označenih od 0-11: POI2_0 do PIO2_11.
    PIO3 ima na razpolago 4 nožice označene z 0-3: POI3_0 do PIO3_3.
    4 nožice so na voljo za napajanje – 2x Vdd (+3,3V), 2x Vss (0V),
    2 nožici sta namenjeni priklopu kristla
    2 nožici sta namenjeni priklopu USB signalov DM in DP


Posamezna nožica opravlja lahko različne funkcije. Vse funkcije so navedene na straneh 125-127 (Table 144) UM10375.pdf, hiter pregled pa je na voljo preko slike našega procesorja na strani 120 (Fig 10).

Če hočemo, da procesor na I/O enoto pošilja podatke, moramo enoto ustrezno nastaviti.
Delovanje posamezne I/O enote krmilimo z registri, ki se imenujejo GPIO0 – GPIO3.
Za posamezno I/O enoto imamo na razpolago več GPIO registrov, s katerimi nastavljamo različne funkcije za posamezen pin. Ni nujno, da so vse funkcije na voljo za vsak pin.
Preko posameznega GPIO registra lahko nastavimo obnašanje posameznega pina I/O enote.
Za GPIO0 so na voljo:
    GPIO0DATA
    GPIO0DIR

ter drugi, ki nas v tem trenutku ne zanimajo.
Detajlni podatki o GPIO0 se nahajajo na strani 132 UM10375.pdf.

GPIO0DATA – je register, ki določa kakšen podatek je vpisan na posamezen pin PIO0 I/O enote (1 ali 0). Če je posamezen pin nastavljen za vhod ali kakšno drugo funkcijo vrednost v tem registru ne vpliva nanj.
GPIO0DIR – je register, ki določa ali je posamezen pin PIO0 I/O enote vhod ali izhod. 0 je vhod, 1 je izhod.

Kako določen bit nastaviti?
Žal v C jeziku ne moremo direktno nasloviti samo en bit informacije v nekem registru. Zato je potrebno nasloviti celoten register, kar pa zna biti problematično če nočemo spreminjati določenih bitov. Zato je ukaz za pošiljanje bita (1) na PIO0 pin 8 takšen:

Koda:
LPC_GPIO0->DATA |=  (1<<8);


Kako se pa to izvede?
(1<<8) pomeni, da se na najnižji bit začasnega registra vpiše 1 nato pa premakne za 8 mest v levo.
Tako dobimo:
0000 0000 0000 0001 -> vpišemo 1 na najnižji bit registra
0000 0001 0000 0000 -> premaknemo za 8 mest v levo

|= pomeni, da se dobljena vrednost v začasnem registru prišteje obstoječi vrednosti, ki je v registru, ki ga naslavljamo (GPIO0DATA). »| » je znak za binarni ali

Če je vrednost v GPIO0DATA:
0000 0000 0000 0000
0000 0001 0000 0000 | (ali)
--------------------------
0000 0001 0000 0000 -> rezultat v registru GPIO0DATA

Opisani postopek torej spremeni le en bit v registru GPIO0DATA.

Kako pa določen bit pobrisati?
Postopek je podoben, le nekaj črk je dodanih:
Koda:

LPC_GPIO0->DATA &= ~(1<<8)


znak ~ pomeni, da je vrednost invertirana tako iz podatka
0000 0001 0000 0000 dobimo
1111 1110 1111 1111

Tako dobimo, če je v GPIO0DATA:
1110 1001 0110 0000
1111 1110 1111 1111 & (in)
-------------------------
1110 1000 0110 0000 -> rezultat v registru GPIO0DATA

Opisani postopek torej spremeni le en bit v registru GPIO0DATA

Ker pa samo pisanje podatkov v register, če I/O enota ni nastavljena kot izhod ne da nobenega vidnega učinka, je napisan tale preprost programček:

Koda:
#include <stdio.h>         /* tole niti ni potrebno za ta primer */
#include "LPC13xx.h"      /* LPC13xx definicije        */

int main (void) {         /* glavna zanka */
int i;               /* spremenljivka i je tipa int */

LPC_GPIO0->DIR |= (1<<8);   /* |= (ALI) Vpišemo 1 v 8 bit registra DIR (LED=P0.8) 
                    Nastavitev smeri PortaP0(GPIO0) P0=izhod    */   

while (1) {            /* Neskončna zanka*/

LPC_GPIO0->DATA &= ~(1<<8);   /* &= (IN)  Vpišemo 0 v 8 bit registra DATA  prižge LED 2 */
   for (i=0;i<1000000;i++);
LPC_GPIO0->DATA |=  (1<<8);   /* |= (OR)  Vpišemo 1 v 8 bit registra DATA  ugasne LED2 */
   for (i=0;i<1000000;i++);
}
}



Kako programček deluje?
    - int main (void) {} je glavna programska zanka
    - »i« je definirana kot spremenljivka tipa integer (celo številčno število)
    - LPC_GPIO0->DIR |= (1<<8); Bit 8 registra GPIO0 je nastavljen kot izhod – je postavljen na 1. GPIO0.8 je v bistvu pin PIO0.8, na katerem je naša LED z oznako 2. - Glej shemo.pdf. Ker so LED diode vezane fiksno na VCC, se lahko prižgejo le tako, da se izhod procesorja postavi na 0.
    - while (1) {} je neskončna zanka, ki se izvaja dokler procesorja ne resetiramo.
    - LPC_GPIO0->DATA &= ~(1<<8); izhod PIO0.8 postavimo na 0 – LED se prižge
    - for (i=0;i<1000000;i++); preprost časovnik, ki je odvisen od hitrosti kristala procesorja. Kako zadeva deluje? Spremenljivko postavimo na 0 (i=0) v naslednjem koraku jo povečamo za 1 (i++) in to ponavljamo do 999999 (i<1000000) Procesor se vrti v krogu dokler ne prešteje 1000000 ciklov.
    Ko konča skoči na naslednjo vrstico
    - LPC_GPIO0->DATA |= (1<<8); izhod PIO0.8 postavimo na 1 – LED se ugasne, sledi ponovno pavza
    for (i=0;i<1000000;i++);
    - Dioda pri 12MHz kristalu procesorja in privzetih nastavitvah utripa s hitrostjo cca 4Hz



Iz kje sem pa potegnil ukaze LPC_GPIO0 in DATA ter DIR?
Zapisani so v datoteki LPC13xx.h, kjer so definirani ukazi, ki jih lahko uporabimo:
Začnejo se pri vrstici 547, nas pa zanima tale:
Koda:
#define LPC_GPIO0             ((LPC_GPIO_TypeDef   *) LPC_GPIO0_BASE )


Ter seveda vrstica 320, kjer je pričetek definicije:
typedef struct za naš register LPC_GPIO definicija vsebuje dve besedi, ki nas zanimata: DIR in DATA.

Projekt programčka je pripet spodaj.
Ostane le, da programček prevedemo in naložimo na procesor.

===========================================
Še par povezav:
PDF razvojne ploščice uLPC1000
Razvojno okolje Keil - demo
LPC1343 PDF



Blinky.zip
 Opis:
Projekt Blinky za Keil

Download
 Ime datoteke:  Blinky.zip
 Velikost datoteke:  234.86 KB
 Downloadano:  29 krat


lpcrc.zip
 Opis:
Programček LPCRC - dodatek za Keil

Download
 Ime datoteke:  lpcrc.zip
 Velikost datoteke:  19.77 KB
 Downloadano:  24 krat


shema.pdf
 Opis:
Električna shema TIV (Samo povzetek)

Download
 Ime datoteke:  shema.pdf
 Velikost datoteke:  17.79 KB
 Downloadano:  40 krat


_________________
If at first you don't succeed, destroy all evidence that you tried.
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo Obišči avtorjevo spletno stran
Highlag
Član
Član



Pridružen-a: Pet 23 Jan 2004 20:42
Prispevkov: 4034
Aktiv.: 18.17
Kraj: Črnuče

PrispevekObjavljeno: Ned Jul 15, 2012 12:31 pm    Naslov sporočila:  2 del Odgovori s citatom

Del 2: Define

Ukaz #define prevajalniku pove, da naj v kodi, ki jo prevaja določen izraz zamenja z drugim. Uporaba je enostavna in smiselna, saj bistveno poveča berljivost kode, in hkrati omogoča hitro spreminjanje parametrov, če je to potrebno.
Primer kode:

Koda:
#include <stdio.h>
#include "LPC13xx.h"           // LPC13xx definitions


int main (void) {              // Main Program             
int i;                         // spremenljivka i je tipa int
LPC_GPIO0->DIR |= (1<<8);      // |= (ALI) Vpišemo 1 v 8 bit  registra DIR GPIO0.8,  P0.8=izhod  LED2
LPC_GPIO0->DIR |= (1<<9);      // |= (ALI) Vpišemo 1 v 9 bit  registra DIR GPIO0.9,  P0.9=izhod  LED3
LPC_GPIO1->DIR |= (1<<10);     // |= (ALI) Vpišemo 1 v 10 bit registra DIR GPIO1.10, P1.10=izhod LED4
LPC_GPIO2->DIR |= (1<<2);      // |= (ALI) Vpišemo 1 v 2 bit  registra DIR GPIO2.2,  P2.2=izhod  LED1
LPC_GPIO2->DIR |= (1<<10);     // |= (ALI) Vpišemo 1 v 10 bit registra DIR GPIO2.10, P2.10=izhod LED8
LPC_GPIO3->DIR |= (1<<0);      // |= (ALI) Vpišemo 1 v 0 bit  registra DIR GPIO3.0,  P3.0=izhod  LED5   
   
   while (1) {                 // Loop forever               
            
   LPC_GPIO2->DATA |= (1<<2);  // |= (OR)    Vpiše      1 v 2  bitu registra DATA GPIO2.2  ugasne LED1
   LPC_GPIO0->DATA ^= (1<<8);  // ^= (XOR) Zamenja stanje v 8  bitu registra DATA GPIO0.8  prižge LED2
   LPC_GPIO0->DATA |= (1<<9);  // |= (OR)    Vpiše      1 v 9  bit  registra DATA GPIO0.9  ugasne LED3
   LPC_GPIO1->DATA ^= (1<<10); // ^= (XOR) Zamenja stanje v 10 bitu registra DATA GPIO1.10 prižge LED4
   LPC_GPIO3->DATA |= (1<<0);  // |= (OR)    Vpiše      1 v 0  bit  registra DATA GPIO3.0  ugasne LED5
   LPC_GPIO2->DATA ^= (1<<10); // ^= (XOR) Zamenja stanje v 10 bitu registra DATA GPIO2.10 prižge LED8   
   for (i=0;i<1000000;i++);
   LPC_GPIO2->DATA ^= (1<<2);  // ^= (XOR) Zamenja stanje v 2  bitu registra DATA GPIO2.2  prižge LED1
   LPC_GPIO0->DATA |= (1<<8);  // |= (OR)    Vpiše      1 v 8  bit  registra DATA GPIO0.8  ugasne LED2
   LPC_GPIO0->DATA ^= (1<<9);  // ^= (XOR) Zamenja stanje v 9  bitu registra DATA GPIO0.9  prižge LED3
   LPC_GPIO1->DATA |= (1<<10); // |= (OR)    Vpiše      1 v 10 bit  registra DATA GPIO1.10 ugasne LED4
   LPC_GPIO3->DATA ^= (1<<0);  // ^= (XOR) Zamenja stanje v 0  bitu registra DATA GPIO3.0  prižge LED5
   LPC_GPIO2->DATA |= (1<<10); // |= (OR)    Vpiše      1 v 10 bit  registra DATA GPIO2.10 ugasne LED8   
   for (i=0;i<1000000;i++);
   }
}


Spodaj pa je koda, ki je prevedena identična. Le izgleda precej drugače


Koda:
#include <stdio.h>
#include "LPC13xx.h"             //LPC13xx definitions

#define LED2 (1<<8)              // P0.8
#define LED3 (1<<9               // P0.9
#define LED4 (1<<10)             // P1.10
#define LED1 (1<<2)              // P2.2
#define LED8 (1<<10              // P2.10
#define LED5 (1<<0)              // P3.0
#define zakasnitev 1000000       // številka, ki določa hitrost utripanja


int main (void) {                // Main Program             
int i;                           // spremenljivka i je tipa int
LPC_GPIO0->DIR |= LED2;          // |= (ALI) Vpišemo 1 v 8 bit  registra DIR GPIO0.8,  P0.8=izhod  LED2
LPC_GPIO0->DIR |= LED3;          // |= (ALI) Vpišemo 1 v 9 bit  registra DIR GPIO0.9,  P0.9=izhod  LED3
LPC_GPIO1->DIR |= LED4;          // |= (ALI) Vpišemo 1 v 10 bit registra DIR GPIO1.10, P1.10=izhod LED4
LPC_GPIO2->DIR |= LED1;          // |= (ALI) Vpišemo 1 v 2 bit  registra DIR GPIO2.2,  P2.2=izhod  LED1
LPC_GPIO2->DIR |= LED8;          // |= (ALI) Vpišemo 1 v 10 bit registra DIR GPIO2.10, P2.10=izhod LED8
LPC_GPIO3->DIR |= LED5;          // |= (ALI) Vpišemo 1 v 0 bit  registra DIR GPIO3.0,  P3.0=izhod  LED5   
   
while (1) {                      // Loop forever tule se izvaja naš program   
                                          
   LPC_GPIO2->DATA |= LED1;      // |= (OR)  Vpiše        1 v 2  bitu registra DATA GPIO2.2  ugasne LED1
   LPC_GPIO0->DATA ^= LED2;      // ^= (XOR) Zamenja stanje v 8  bitu registra DATA GPIO0.8  prižge LED2
   LPC_GPIO0->DATA |= LED3;      // |= (OR)  Vpiše        1 v 9  bit  registra DATA GPIO0.9  ugasne LED3
   LPC_GPIO1->DATA ^= LED4;      // ^= (XOR) Zamenja stanje v 10 bitu registra DATA GPIO1.10 prižge LED4
   LPC_GPIO3->DATA |= LED5;      // |= (OR)  Vpiše        1 v 0  bit  registra DATA GPIO3.0  ugasne LED5
   LPC_GPIO2->DATA ^= LED8;      // ^= (XOR) Zamenja stanje v 10 bitu registra DATA GPIO2.10 prižge LED8   
   for (i=0;i<zakasnitev;i++);
   LPC_GPIO2->DATA ^= LED1;      // ^= (XOR) Zamenja stanje v 2  bitu registra DATA GPIO2.2  prižge LED1
   LPC_GPIO0->DATA |= LED2;      // |= (OR)  Vpiše        1 v 8  bit  registra DATA GPIO0.8  ugasne LED2
   LPC_GPIO0->DATA ^= LED3;      // ^= (XOR) Zamenja stanje v 9  bitu registra DATA GPIO0.9  prižge LED3
   LPC_GPIO1->DATA |= LED4;      // |= (OR)  Vpiše        1 v 10 bit  registra DATA GPIO1.10 ugasne LED4
   LPC_GPIO3->DATA ^= LED5;      // ^= (XOR) Zamenja stanje v 0  bitu registra DATA GPIO3.0  prižge LED5
   LPC_GPIO2->DATA |= LED8;      // |= (OR)  Vpiše        1 v 10 bit  registra DATA GPIO2.10 ugasne LED8   
   for (i=0;i<zakasnitev;i++);
   }
}



Bistvena novost so spodnji stavki
Koda:

#define LED2 (1<<8)         // P0.8
#define LED3 (1<<9)         // P0.9
#define LED4 (1<<10)        // P1.10
#define LED1 (1<<2)         // P2.2
#define LED8 (1<<10)        // P2.10
#define LED5 (1<<0)         // P3.0
#define zakasnitev 1000000  // številka, ki določa hitrost utripanja


Z njimi priredimo kriptičnim ukazom bolj berljivo obliko, ki jo lahko uporabimo skozi celotno našo kodo. Če LED 2 prestavimo na drugo mesto, je potrebno ukaz spremeniti samo na enem mestu.
Pri kratki kodi, kot je dani primer je to relativno enostavno, ko pa se koda napihne čez več strani pa pregledovanje postane hudo težavno.

Edit: Sem popravil malo obliko, pa podatek kdaj je LED prizgana



Define1.zip
 Opis:
Brez #define

Download
 Ime datoteke:  Define1.zip
 Velikost datoteke:  238.09 KB
 Downloadano:  11 krat


Define2.zip
 Opis:
Z #define

Download
 Ime datoteke:  Define2.zip
 Velikost datoteke:  238.61 KB
 Downloadano:  8 krat


_________________
If at first you don't succeed, destroy all evidence that you tried.
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo Obišči avtorjevo spletno stran
Highlag
Član
Član



Pridružen-a: Pet 23 Jan 2004 20:42
Prispevkov: 4034
Aktiv.: 18.17
Kraj: Črnuče

PrispevekObjavljeno: Ned Jul 15, 2012 7:10 pm    Naslov sporočila:   Odgovori s citatom

Del 3: Uporaba tipk
Naša razvojna ploščica ima 2 tipki. Prva z imenom RESET je vezana preko nekaj elementov na reset pin procesorja P0.0, druga z imenom INT pa na P0.1 – glej shemo.pdf.
Ker pritisk na RESET tipko dejansko resetira procesor, za naš namen ni preveč uporabna.
Lahko se njen namen spremeni, a bi bilo potem treba vezje programirati na drugačen način.
Za test smo tako uporabili tipko INT.

Če hočemo uporabiti tipko mora biti pin, na katerega je vezana definiran kot vhod. Toda koda v našem programu (glej spodaj) tega nikjer eksplicitno ne navaja.
Zakaj? Procesor ob zagonu pine postavi na določene funkcije. Kakšno nalogo bo določen pin ob zagonu opravljal si lahko pogledate v datoteki um10375.pdf od strani 124 naprej. Za pin, ki nas zanima (P0.1) piše, da je ob zagonu vhod. Zato posebna konfiguracija ni potrebna.

Če pa bi pin želeli vseeno nastaviti za vhod pa to lahko storimo z ukazom:
Koda:
LPC_GPIO0->DIR &= ~tipka   // &= (AND) ~ = invertirana vrednost Vpišemo 0 v 1 bit registra DIR GPIO.1 P0.1=vhod tipka


Koda programčka zgleda takole:
Koda:
#include <stdio.h>
#include "LPC13xx.h"          //LPC13xx definitions

#define LED2 (1<<8)           // P0.8
#define LED3 (1<<9)           // P0.9
#define LED4 (1<<10)          // P1.10
#define LED1 (1<<2)           // P2.2
#define LED8 (1<<10)          // P2.10
#define LED5 (1<<0)           // P3.0
#define zakasnitev 1000000    // številka, ki določa hitrost utripanja
#define tipka (1<<1)          // Tipka INT je vezana na P0.1

int main (void)               // Main Program
{
int i;                        // spremenljivka i je tipa int
LPC_GPIO0->DIR |= LED2;       // |= (OR) Vpišemo 1 v 8 bit  registra DIR GPIO0.8,  P0.8=izhod  LED2
LPC_GPIO0->DIR |= LED3;       // |= (OR) Vpišemo 1 v 9 bit  registra DIR GPIO0.9,  P0.9=izhod  LED3
LPC_GPIO1->DIR |= LED4;       // |= (OR) Vpišemo 1 v 10 bit registra DIR GPIO1.10, P1.10=izhod LED4
LPC_GPIO2->DIR |= LED1;       // |= (OR) Vpišemo 1 v 2 bit  registra DIR GPIO2.2,  P2.2=izhod  LED1
LPC_GPIO2->DIR |= LED8;       // |= (OR) Vpišemo 1 v 10 bit registra DIR GPIO2.10, P2.10=izhod LED8
LPC_GPIO3->DIR |= LED5;       // |= (OR) Vpišemo 1 v 0 bit  registra DIR GPIO3.0,  P3.0=izhod  LED5
 
while (1)                     // Loop forever tule se izvaja naš program   
  {
  if (!(LPC_GPIO0->DATA & tipka))
    {
    LPC_GPIO2->DATA |= LED1;  // |= (OR)  Vpiše        1 v 2  bitu registra DATA GPIO2.2  ugasne LED1
    LPC_GPIO0->DATA ^= LED2;  // ^= (XOR) Zamenja stanje v 8  bitu registra DATA GPIO0.8  prižge LED2
    LPC_GPIO0->DATA |= LED3;  // |= (OR)  Vpiše        1 v 9  bit  registra DATA GPIO0.9  ugasne LED3
    LPC_GPIO1->DATA ^= LED4;  // ^= (XOR) Zamenja stanje v 10 bitu registra DATA GPIO1.10 prižge LED4
    LPC_GPIO3->DATA |= LED5;  // |= (OR)  Vpiše        1 v 0  bit  registra DATA GPIO3.0  ugasne LED5
    LPC_GPIO2->DATA ^= LED8;  // ^= (XOR) Zamenja stanje v 10 bitu registra DATA GPIO2.10 prižge LED8
    for (i=0;i<zakasnitev;i++);
    LPC_GPIO2->DATA ^= LED1;  // ^= (XOR) Zamenja stanje v 2  bitu registra DATA GPIO2.2  prižge LED1
    LPC_GPIO0->DATA |= LED2;  // |= (OR)  Vpiše        1 v 8  bit  registra DATA GPIO0.8  ugasne LED2
    LPC_GPIO0->DATA ^= LED3;  // ^= (XOR) Zamenja stanje v 9  bitu registra DATA GPIO0.9  prižge LED3
    LPC_GPIO1->DATA |= LED4;  // |= (OR)  Vpiše        1 v 10 bit  registra DATA GPIO1.10 ugasne LED4
    LPC_GPIO3->DATA ^= LED5;  // ^= (XOR) Zamenja stanje v 0  bitu registra DATA GPIO3.0  prižge LED5
    LPC_GPIO2->DATA |= LED8;  // |= (OR)  Vpiše        1 v 10 bit  registra DATA GPIO2.10 ugasne LED8
    for (i=0;i<zakasnitev;i++);
    }
  else
    {
    LPC_GPIO2->DATA |= LED1;  // |= (OR)  Vpiše        1 v 2  bitu registra DATA GPIO2.2  ugasne LED1
    LPC_GPIO0->DATA |= LED2;  // |= (OR)  Vpiše        1 v 8  bit  registra DATA GPIO0.8  ugasne LED2
    LPC_GPIO0->DATA |= LED3;  // |= (OR)  Vpiše        1 v 9  bit  registra DATA GPIO0.9  ugasne LED3
    LPC_GPIO1->DATA |= LED4;  // |= (OR)  Vpiše        1 v 10 bit  registra DATA GPIO1.10 ugasne LED4
    LPC_GPIO3->DATA |= LED5;  // |= (OR)  Vpiše        1 v 0  bit  registra DATA GPIO3.0  ugasne LED5
    LPC_GPIO2->DATA |= LED8;  // |= (OR)  Vpiše        1 v 10 bit  registra DATA GPIO2.10 ugasne LED8
    }
  }
}


V kodi se je znašel nov ukaz if, za njim pa (!(LPC_GPIO0->DATA & tipka))

Ukaz if je pogojni stavek.
struktura je takšna:

if (pogoj) {stavek 1 - izvede se, če je pogoj true}
else {stavek 2 - izvede se če je pogoj false}

Ni pa nujno, da napišemo celoten stavek
Lako uporabimo samo del:
if (pogoj) {stavek 1 – izvede se, če je pogoj true}

Torej v naši kodi pogoj if preverja ali je izraz (!(LPC_GPIO0->DATA & tipka)) enak true

LPC_GPIO0->DATA je register z vsebino, ki vsebuje tudi stanje pina P0.1.
tipka je definicija lokacije naše tipke (1<<1) - P0.1

Torej z ukazom LPC_GPIO0->DATA & tipka procesor binarno sešteje vrednost podatkov v registru GPIO0 DATA in podatkom o lokaciji, ki nas zanima.
Tipka je preko upora vezana na +3,3V, kar pomeni, da je privzeto (ko tipka ni pritisnjena) na vhodu P0.1=1. Ko pritisnemo tipko – le ta potegne vhod na 0V – na vhodu dobimo 0.
Zato je pred izrazom še »!«, ki celoten izraz negira.

Izraz bi se torej bralo takole:
če je P0.1=0
{
izvedi stavek 1
}
else
{
izvedi stavek 2
}

Kaj pa program dela? Ob pritisku izmenično utripajo LED, ki so na razpolago na ploščici, ko tipko spustimo LED diode ugasnejo.



Uporaba_tipke.zip
 Opis:
Uporaba tipke

Download
 Ime datoteke:  Uporaba_tipke.zip
 Velikost datoteke:  239.43 KB
 Downloadano:  8 krat


_________________
If at first you don't succeed, destroy all evidence that you tried.
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo Obišči avtorjevo spletno stran
Highlag
Član
Član



Pridružen-a: Pet 23 Jan 2004 20:42
Prispevkov: 4034
Aktiv.: 18.17
Kraj: Črnuče

PrispevekObjavljeno: Tor Jul 17, 2012 5:46 pm    Naslov sporočila:   Odgovori s citatom

Del 4: Serijska komunikacija
Prej ali slej pridemo do točke, ko je potrebno s procesorjem komunicirati s kakšno drugo napravo. Ena izmed enostavnejših in hkrati precej razširjenih zmožnosti je serijska komunikacija. Pri tem seveda mislim na serijsko komunikacijo ki je zelo podobna RS232 komunikaciji. V čem so razlike? predvsem v napetostnih nivojih in dodatnih kontrolnih signalih, saj se tule vse skupaj dogaja na RX in TX signalnih vodih.

Za enostavnejšo komunikacijo, ki omogoča prenos posameznih znakov so za nas pri Keilu že spisali preprosto knjižnico serial.c, ki jo je preko datoteke glave serial.h kličemo iz našega programa.
Kaj pa vsebuje serial.h?
Tole:
Koda:
extern void SER_init (void);
extern int sendchar (int c);
extern int chkkey (void);
extern int getkey (void);


Vsebuje torej definicije funkcij, ki ji lahko kličemo iz našega programa:
SER_init
Funkcija za inicializacijo serijske komunikacije – brez klica te funkcije serijska komunikacija ne bo delovala
sendchar
Funkcija, ki jo lahko uporabimo za pošiljanje znaka na serijski izhod.
chkkey
Funkcija, ki preveri ali je v medpomnilnik serijskega vhoda prispel podatek
getkey
Funkcija, ki prevzame prejeti podatek iz medpomnilnika serijskega vhoda.

Procesor LPC1343 ima vgrajen medpomnilnik dolžine 16 bajtov za pošiljanje in sprejemanje.

Opise posameznih funkcij lahko preberemo v serial.c, ki mora biti pred poizkusom prevajanja vključena v naš projekt.
Takole na hitro:
SER_init
Vsebuje nastavitve našega serijskega porta. Najbolj zanimive so naslednje vrstice
Koda:
  LPC_IOCON->PIO1_6  =  (1UL <<  0);    /* P1.6 is RxD                */
  LPC_IOCON->PIO1_7  =  (1UL <<  0);    /* P1.7 is TxD                */
  LPC_UART->LCR = 0x83;                 /* 8 bits, no Parity, 1 Stop bit    */
  LPC_UART->DLL = 4;                    /* 115200 Baud Rate @ 12.0 MHZ PCLK */
  LPC_UART->FDR = 0x85;                 /* FR 1.627, DIVADDVAL 5, MULVAL 8  */


Z njimi nastavimo RX in TX pin , lastnosti prenosa, ter hitrost prenosa.

Pa razložimo še nekaj podrobnosti:
P1.6 in P1.7 Sta uporabljena za serijsko komunikacijo zato, ker imata to funkcijo podprto že s strojno opremo. Da pa ju lahko uporabimo ju je potrebno ustrezno nastaviti.

Registru LPC_IOCON->PIO1_6 nastavimo prvi bit na 1 kako?
To stori ukaz (1UL <<0)
Register IOCON_PIO1_6 je dolg 32 bitov. Zato je uporabljen zapis 1UL kar pomeni, da je številka 1 zapisana na način unsigned long int.
Long int 1L ima lahko vrednost med -65536 ter +65536. (-2^16 do +2^16)
Unsigned long int 1UL pa ima lahko vrednost samo v pozitivno smer, zato vrednost po bitih enako dolga vendar samo v eno smer 2^32. Ker z ukazom (1UL<<0) premaknemo 1 za nič bitov v levo dobimo takšno številko:
XXXX XXXX XXXX XXXX XXXX XXXX XXXX XXX1 v binarnem zapisu, X so seveda lahko poljubne vrednosti (1 ali 0). Če sedaj pogledamo v datasheet procesorja UM10375.pdf stran 115 piše 0x1 Selects function RXD – Pin 1.6 smo nastavili za funkcijo RX.

Sledi nastavljanje parametrov delovanja naše povezave:
Koda:
LPC_UART->LCR = 0x83;                 /* 8 bits, no Parity, 1 Stop bit    */

Registru U0LCR, ki je naslovljen z ukazom LPC_UART->LCR priredimo vrednost 0x83, kar v binarnem zapisu znaša:
0000 0000 1000 0011

Če pogledamo datasheet procesorja UM10375.pdf stran 189 stran lahko razberemo kaj posamezni biti pomenijo.
    Prva dva bita določata dolžino znaka – 0x3 = b11 = 8 bitni znaki
    Tretji bit določa ali bo stop bit dolžine 1 ali 2 bita. 0 = b0 = 1 stop bit
    Četrti bit določa ali se uporablja paritetni bit 0 = b0 = ni paritetnega bita
    Peti in šesti bit določata sodost /lihost paritetnega bita 0x0 = b00 = liha pariteta
    Sedmi bit določa kontrolo preloma BC 0 = b0 = ni BC kontrole
    Osmi bit omogoča uporabo delilnikov hitrosti 1 = b1 = je vključeno – omogoča spreminjanje hitrosti


Spreminjanje drugih parametrov pa je kar kompleksno, saj zahteva kar nekaj računanja.
Postopek za nekaj primerov je opisan v datasheetu procesorja UM10375.pdf na straneh 200-202.

Nekaj osnov smo tako spoznali. Sedaj je treba prikazano še uporabiti.
Za to je spisan programček blinky.c:
Koda:
#include <stdio.h>
#include "LPC13xx.h"             // LPC13xx definitions
#include "serial.h"              // preprosta knjižnica za serijsko komunikacijo

#define LED2 (1<<8)              // P0.8 
#define LED3 (1<<9)              // P0.9
#define TIPKA (1<<1)             // Tipka INT je vezana na P0.1

int main (void) {                // Main Program


int i;                           // spremenljivka i je tipa int
int ch;                          // spremenljivka ch je tipa int
LPC_GPIO0->DIR |= LED2;          // |= (ALI) Vpišemo 1 v 8 bit  registra DIR GPIO0.8,  P0.8=izhod  LED2
LPC_GPIO0->DIR |= LED3;          // |= (ALI) Vpišemo 1 v 9 bit  registra DIR GPIO0.9,  P0.9=izhod  LED3
 SER_init();                     // Inicializacija serijskega porta
   while (1) {                    // Neskončna zanka

   if (!(LPC_GPIO0->DATA & TIPKA))// Če je pritisnjena tipka se izvede naslednja vrstica
   {
  sendchar ('c');
   }
  if (chkkey())                  // če je prispel znak
   {
  ch=getkey();                   
      if (ch=='c')                 // ali je prispeli znak c?
      {
          LPC_GPIO0->DATA ^=  LED2 | LED3;  // ^= (XOR)  Spremenimo če je bila prej 1 v 0 in obratno diodi LED2 in LED3
          for (i=0;i<1000000;i++);
        }
   }
}
}

Kako zadeva deluje?
Pred neskončno zanko je klicana funkcija za inicializacijo serijske komunikacije
Nato program čaka, da pritisnemo tipko.
Ob pritisku na tipko s pomočjo funkcije sendchar pošljemo vpisani znak na serijski izhod.
Po poslanemu znaku je takoj napisana poizvedba chkkey, ki preveri, ali je v predpomnilnik prispel kakšen znak. Če je prispel, se znak priredi spremenljivki ch, in takoj nato pogleda ali je bil znak c
V kolikor je bil znak c v naslednjem trenutku LED2 in LED3 spremenita stanje. (Ugasneta ali prižgeta – odvisno od prejšnjega stanja. Da celotna zanka ne dela prehitro je dodana še ena zakasnitev, ki upočasni utripanje.

Da programček je najenostavneje na naši testni ploščici povezati RX in TX pina. To storimo tako, da povežemo pina P1.6 in P1.7 našega procesorja. Na ploščici to zgleda takole:


To pa seveda ni nujno. V kolikor imamo pri roki kakšen USB-serijski vmesnik (sam sem uporabil kar tega: USB-serial )lahko RX, TX ter GND povezave naredimo preko takšnega vmesnika in odziv spremljamo preko terminala na osebnem računalniku. Pri vsem tem je potrebno paziti, da signali niso previsoki. Načeloma serijska komunikacija procesorja dela na 3,3V, lahko do 5V, medtem, ko so napetostni nivoji običajne RS232 serijske komunikacije višji, kar lahko povzroči uničenje procesorja.

Na osebnem računalniku potrebujemo za potrebne serijske komunikacije terminalski programček. Okna imajo že nameščen Terminal, ki za osnovno rabo zadošča, sam pa sem za poizkuse namestil kar programček Bray, katerega avtor je tudi član našega foruma. Najdete ga lahko tule: Terminal.exe

Kako pa lahko pošiljamo znak, če ima funkcija definirano vhodno spremenljivko INT?
Preprosto. Znaki so v bistvu številke. Če pogledamo ASCII tabelo znakov - ena je na vpogled tule: ASCII vidimo, da je posameznemu znaku določena številka, ki ima dolžino enega bajta. Kar pa je INT številka. Seveda naši šumniki nekako izpadejo iz tega seznama. Za to se uporablja različne kodne tabele, kjer so posamezni znaki opisani z večimi bajti podatkov. [/code]



Serijski_vmesnik.zip
 Opis:
Keil projekt za serijski vmesnik

Download
 Ime datoteke:  Serijski_vmesnik.zip
 Velikost datoteke:  240.8 KB
 Downloadano:  13 krat


_________________
If at first you don't succeed, destroy all evidence that you tried.


Nazadnje urejal/a Highlag Čet Jul 19, 2012 4:37 pm; skupaj popravljeno 1 krat
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo Obišči avtorjevo spletno stran
boco
Član
Član



Pridružen-a: Čet 31 Jul 2003 9:42
Prispevkov: 919
Aktiv.: 4.14
Kraj: Ptuj/Kranj/Ljubljana

PrispevekObjavljeno: Sre Jul 18, 2012 5:49 pm    Naslov sporočila:   Odgovori s citatom

@Highlag, že pri prvem delu prispevka sem hotel pohvaliti tvoje dejanje vendar sem čakal, kdaj bo prispevkov konec, ker nisem hotel vmes prekinit izrednega dela. Kapo dol Angel
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo
VolkD
Član
Član



Pridružen-a: Pet 24 Sep 2004 21:58
Prispevkov: 14228
Aktiv.: 64.08
Kraj: Divača (Kačiče)

PrispevekObjavljeno: Sre Jul 18, 2012 6:08 pm    Naslov sporočila:   Odgovori s citatom

No tole bo pa vsekakor treba dati v revijo.
_________________
Dokler bodo ljudje mislili, da živali ne čutijo, bodo živali čutile, da ljudje ne mislijo.
Nazaj na vrh
Skrit Poglej uporabnikov profil Pošlji zasebno sporočilo Obišči avtorjevo spletno stran
RGorazd
Član
Član



Pridružen-a: Čet 20 Maj 2004 15:57
Prispevkov: 1712
Aktiv.: 7.71
Kraj: Ig

PrispevekObjavljeno: Sre Jul 18, 2012 6:23 pm    Naslov sporočila:   Odgovori s citatom

Dodatek k Primoževemu prispevku za serijsko komunikacijo. V kolikor vključimo v Blinky projekt s serijsko komunikacijo datoteko Retarget.c iz Blinkyja, ki smo ga obravnavali na predavanjih, lahko za komunikacijo uporabljamo standardne funkcije kot so printf ter scanf.

Za izpisati neko spremenljivko na RS232 potem uporabimo ukaz:

printf("Naša vrednost je: %i",spremenljivka);

%i pomeni, da imamo opravka s spremenljivko tipa int

lahko uporabljamo spremenljivke tipa char (%c), float (%f) float z dvema decimalnima mestoma (%2f)

Koda:

/* printf example */
#include <stdio.h>

int main()
{
   printf ("Characters: %c %c \n", 'a', 65);
   printf ("Decimals: %d %ld\n", 1977, 650000L);
   printf ("Preceding with blanks: %10d \n", 1977);
   printf ("Preceding with zeros: %010d \n", 1977);
   printf ("Some different radixes: %d %x %o %#x %#o \n", 100, 100, 100, 100, 100);
   printf ("floats: %4.2f %+.0e %E \n", 3.1416, 3.1416, 3.1416);
   printf ("Width trick: %*d \n", 5, 10);
   printf ("%s \n", "A string");
   return 0;
}


Imam pa vprašanje vzvezi z USBCDC primerom. Sam demo uporablja 2 funkciji. V eni prepisuje iz uart-a na USB virtual COM, v drugi pa iz virtual COM porta v UART. zanima me, kako bi lahko preko virtual COM porta poslal kak string ali pa spremenljivko tako kot zgoraj, še najlepše s printf funkcijo. Sam že par dni guglam po raznih forumih, a nisem nikjer našel ustrezne rešitve.

LP G

_________________
.
._. _ _ ._. _.__. _|
[ (_](_)[ (_] /_(_]
._|
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo Obišči avtorjevo spletno stran
Highlag
Član
Član



Pridružen-a: Pet 23 Jan 2004 20:42
Prispevkov: 4034
Aktiv.: 18.17
Kraj: Črnuče

PrispevekObjavljeno: Sre Jul 18, 2012 7:47 pm    Naslov sporočila:   Odgovori s citatom

Hvala pride še PWM, potem bo pa treba še pošteno rokave zavihat, da bo iz vsega tega kaj bolj uporabnega nastalo. Mr. Green
_________________
If at first you don't succeed, destroy all evidence that you tried.
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo Obišči avtorjevo spletno stran
skyflyer
Član
Član



Pridružen-a: Tor 11 Jan 2011 22:35
Prispevkov: 44
Aktiv.: 0.27
Kraj: Ljubljana

PrispevekObjavljeno: Čet Jul 19, 2012 11:01 am    Naslov sporočila:   Odgovori s citatom

Highlag, pohvalno. Zelo lepo si napisal. Osebno imam sicer nekaj tezav z LPC1113, ker deluje malce drugace...
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo
elson2k
Član
Član



Pridružen-a: Pet 23 Okt 2009 18:09
Prispevkov: 1660
Aktiv.: 9.45
Kraj: Novo mesto

PrispevekObjavljeno: Čet Jul 19, 2012 11:37 am    Naslov sporočila:   Odgovori s citatom

Highlag, pohvale vreden prispevek. Zdaj je celo meni marsikaj jasno Mr. Green

Upam, da sledi tudi nadaljevanje Wink

_________________
As every cat owner knows, nobody owns a cat.
Nazaj na vrh
Skrit Poglej uporabnikov profil Pošlji zasebno sporočilo AIM - AOL Instant - naslov MSN Messenger - naslov
manijak
Član
Član



Pridružen-a: Pon 22 Avg 2005 20:19
Prispevkov: 73
Aktiv.: 0.33
Kraj: Koper

PrispevekObjavljeno: Čet Jul 19, 2012 11:08 pm    Naslov sporočila:   Odgovori s citatom

Highlag kapo dol. Nekaj takega sem čakal že kar nekaj časa Smile
_________________
LP Jan
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo Pošlji E-sporočilo
Highlag
Član
Član



Pridružen-a: Pet 23 Jan 2004 20:42
Prispevkov: 4034
Aktiv.: 18.17
Kraj: Črnuče

PrispevekObjavljeno: Pet Jul 20, 2012 8:21 pm    Naslov sporočila:   Odgovori s citatom

Del 5. Uporaba PWM.
Kot verjetno vsi vemo PWM potrebuje 2 parametra za delovanje. Ena je frekvenca signala, drug pa širina signala.

Pri uporabi PWM funkcij gre v bistvu za uporabo časovnikov. Naš procesor ima na voljo več časovnikov, ki zmorejo poganjati PWM. Na razpolago sta 2 16 bitna časovnika: TMR16B0 ter TMR16B1, ter 2 32 bitna časovnika TMR32B0 ter TMR32B1.

Uporaba 16 ali 32 bitnih časovnikov je praktično enaka le registri imajo drugačno ime.
V našem primeru bomo uporabili izhoda PIO0_8 in PIO0_9, ki oba uporabljata register CT16B0 in s tem časovnik TMR16B0.

Za začetek je potrebno časovnike omogočiti. (Procesor ima večino funkcij izklopljenih zato, da zmanjša porabo)
To se stori z ukazom:
LPC_SYSCON->SYSAHBCLKCTRL s katerim v register AHB v bite 7-10 vpišemo katere časovnike hočemo vključiti.
(glej stran 25 datoteke UM10375.pdf)

Nato moramo naš naš časovnik nastaviti, da bo deloval v PWM načinu.
Temu služi ukaz LPC_TMR16B0->PWMC s katerim v register TMR16B0 vpišemo kateri kanali časovnika so namenjeni PWM in s tem vključimo PWM prožilcev, ki so določeni posameznim izhodnim pinom – Oznaka MATx. Če vpišemo v prvi bit registra TMR16B0PWMC 1. se vključi PWM za register MAT0, ker je funkcija CT16B0_MAT0 povezana s pinom PIO0_8 in pin je PWM izhod.

Pini, ki jih lahko priključimo na timerje za PWM so naslednji:
(Glej shemo procesorja na strani 120 datoteke UM10375.pdf )

    PIO0_8 na CT16B0_MAT0
    PIO0_9 na CT16B0_MAT1
    PIO0_10 na CT16B0_MAT2
    PIO1_9 na CT16B1_MAT0
    PIO1_10 na CT16B1_MAT1
    PIO1_1 na CT32B1_MAT0
    PIO1_2 na CT32B1_MAT1
    PIO1_3 na CT32B1_MAT2
    PIO1_4 na CT32B1_MAT3
    PIO1_6 na CT32B0_MAT0
    PIO1_7 na CT32B0_MAT1
    PIO0_1 na CT32B0_MAT2
    PIO0_11 na CT32B0_MAT3


Kot vidimo so na posamezen časovnik vezani do 4 izhodi. To pomeni, da lahko z enim časovnikom kmilimo do 4 PWM signale, pri čemer pa je jasno, da en časovnik omogoča eno skupno frekvenco signala vsem izhodom hkrati, širina pulzov pa se lahko nastavi za vsak izhod posebej.

Sledi nastavljanje izhodov, da bodo omogočali uporabo PWM. Za to uporabimo za PIO0_9 ukaz:
Koda:
LPC_IOCON->PIO0_9 |= 0x02;

z vpisom 0x02 v register IOCON_PIO0_9 izberemo način dela PIO0_9 izhoda v našem primeru je to funkcija CT16B0_MAT1, ki je povezana s časovnikom TMR16B0.
(glej stran 104 datoteke UM10375.pdf)

Nastaviti moramo še parametre PWM.

Spodnji ukaz nastavi frekvenco našega PWM signala
Koda:
LPC_TMR16B0->MR3  = 28798;

Ukaz vpiše vrednost 28798 v MR3 register časovnika TMR16B0

Da časovnik ve kateri signali skrbijo za njegovo proženje je uporabljen naslednji ukaz:
Koda:
LPC_TMR16B0->MCR  |= (1 << 10); 

Ukaz vpiše 1 v 10 bit registra MCR.
(Razlaga je na strani 272 datoteke UM10375.pdf)

Ob nastavitvi 10 bita se vključi zastavica MR3R, ki resetira števec časovnika (TC) ko števec prišteje do vrednosti, ki je vpisana v MR3 register. Kaj to pomeni? Ko se števec vključi prične povečevati vrednost TC. Hitrost povečevanja je v našem primeru (glede na nastavitve v prvem delu tega poglavja) enaka hitrosti procesorja torej 72000000 x na sekundo. (72MHz). Ko je vrednost v TC enaka MR3 se vrednost TC resetira in števec prične šteti od začetka.

Če malo poračunamo:
Čas 1 periode pri 72MHz je 13,888 e-9 s
MR3 je nastavljen na 28798. Torej en cikel štetja traja 28798 x 13,888e-9 = 0,4e-3s.
Če to pretvorimo v frekvenco znese 2500.1766Hz, kar je precej podobno 2,5KHz.
To je nosilna frekvenca našega PWM signala.

Kaj pa širina signala?
Naš PIO0_9 izhod uporablja MAT1 register, za identifikacijo.
Spodnji ukaz nastavi širino pulza na PIO0_9
Koda:
LPC_TMR16B0->MR1  = 7200;

Ukaz vpiše vrednost 7200 vMR1 register

Vrednost MR1 mora biti v območju med 0 in vrednostjo MR3. Njegova velikost pa določa širino pulza. Če MR1 izberemo za polovico MR3 bo imel naš signal razmerje 1/0 ravno 50%.
Manjša številka pomeni, da bo razmerje 1/0 manjše -vrednost 7200 je nekje 25%. To pomeni, da bo 1 dolžine 25%, 0 pa 75%.
Zaradi priklopa LED diod na vezju se pa to odraža ravno obratno. Pri daljši 0 diode dalj časa svetijo in so zato svetlejše.

Seveda je potrebno časovnik tudi omogočiti z ukazom.
Koda:
LPC_TMR16B0->TCR  = 1;

(stran 271 datoteke UM10375.pdf)

Končen rezultat je potem programček , ki krmili 2 LED diodi vezani na PIO0_8 in PIO0_9, ki utripata s hitrostjo 2500 x na sekundo svetita pa 25 oziroma 75%. .

Koda:
#include <stdio.h>
#include "LPC13xx.h"                        // LPC13xx definitions

#define LED2 (1<<8)                         // P0.8 LED2
#define LED3 (1<<9)                         // P0.9 LED3

int main (void) {                           // Main Program   

LPC_GPIO0->DIR |= LED2 | LED3;              // |= (ALI) Vpišemo 1 v 8 bit registra DIR (LED=P0.8, P0.9) izhodi
                                            // Nastavitev smeri PortaP0(GPIO0) je izhod
LPC_SYSCON->SYSAHBCLKCTRL |= (1<<7);        // vključi uro za CT16B0 register
LPC_SYSCON->SYSAHBCLKCTRL |= ((1UL <<  6)|  // vključi uro za GPIO
                              (1UL << 16)); // vključi uro za IOCON
LPC_IOCON->PIO0_9 |= 0x02;                  // 0000 0010 - PIO0_9 je priključen na CT16B0_MAT1 register
LPC_IOCON->PIO0_8 |= 0x02;                  // 0000 0010 - PIO0_8 je priključen na CT16B0_MAT0 register

LPC_TMR16B0->MCR  |= (1 << 10);             // 0000 0100 0000 0000 MR3R=1 - TC resetiran ko TC doseže vrednost MR3
LPC_TMR16B0->MR0  = 21598;                  // duty cycle 21598=75%, 7200=25% pri frekvenci 2,5KHz za PIO0_8 LED2
LPC_TMR16B0->MR1  = 7200;                   // duty cycle 14399=50%, 7200=25% pri frekvenci 2,5KHz za PIO0_9 LED3
LPC_TMR16B0->MR3  = 28798;                  // frekvenca 28798=2,5KHz, 14399=5KHz
LPC_TMR16B0->PWMC |= (1<<0);                // vključi PWM za CT16Bn MAT0  PIO0_8
LPC_TMR16B0->PWMC |= (1<<1);                // vključi PWM za CT16Bn MAT1  PIO0_9
LPC_TMR16B0->TCR  = 1;                      // TC + PC enabled

while (1) {                                 // Loop forever
           
}


Še nekaj, malo sem se igral tudi z nastavitvami in nosilna frekvenca PWM gre nekje do 2MHz. Potem pa postane verjetno zaradi kapacitivnosti? preveč občutljiva. LED diode sicer še vedno svetijo, ko pa se s sondo osciloskopa diode dotaknemo pa dioda kar pomežikne.



Pwm.zip
 Opis:
Projekt PWM za Keil

Download
 Ime datoteke:  Pwm.zip
 Velikost datoteke:  239.14 KB
 Downloadano:  6 krat


_________________
If at first you don't succeed, destroy all evidence that you tried.
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo Obišči avtorjevo spletno stran
boco
Član
Član



Pridružen-a: Čet 31 Jul 2003 9:42
Prispevkov: 919
Aktiv.: 4.14
Kraj: Ptuj/Kranj/Ljubljana

PrispevekObjavljeno: Pon Jul 23, 2012 4:57 pm    Naslov sporočila:   Odgovori s citatom

Carsko Applause

Mogoče eno vprašanje oziroma bi potreboval "podnapise", čeprav mi je uspelo pripravit okolje za nov projekt.

Ko odpiramo nov projekt kaj dejansko naredim s tem:

- V urejevalnem oknu kliknemo na mapo Source group 1 in kliknemo na gumb Add files.
- Odpre se okno za izbiro datoteke. Najti moramo tole: C:\Keil\ARM\Boards\Keil\MCB1000\MCB1313\Blinky\system_LPC13xx.c
- Izberemo in potrdimo, nato pa kliknemo gumb OK. Okno se zapre in v mapi Source group 1 se pojavi datoteka system_LPC13xx.c.


A s tem izberemo tip razvojne plošče MCB1000\MCB1313\Blinky ali ???
Hvala
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo
Highlag
Član
Član



Pridružen-a: Pet 23 Jan 2004 20:42
Prispevkov: 4034
Aktiv.: 18.17
Kraj: Črnuče

PrispevekObjavljeno: Pon Jul 23, 2012 10:01 pm    Naslov sporočila:   Odgovori s citatom

Ne to so razne definicije za naš procesor. Nima plošča nič zraven.
_________________
If at first you don't succeed, destroy all evidence that you tried.
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo Obišči avtorjevo spletno stran
boco
Član
Član



Pridružen-a: Čet 31 Jul 2003 9:42
Prispevkov: 919
Aktiv.: 4.14
Kraj: Ptuj/Kranj/Ljubljana

PrispevekObjavljeno: Pon Jul 23, 2012 10:14 pm    Naslov sporočila:   Odgovori s citatom

OK, THX
Nazaj na vrh
Odsoten Poglej uporabnikov profil Pošlji zasebno sporočilo
Pokaži sporočila:   
Objavi novo temo   Odgovori na to temo   Printer-friendly version    www.elektronik.si Seznam forumov -> ARM arhitektura Časovni pas GMT + 2 uri, srednjeevropski - poletni čas
Pojdi na stran 1, 2  Naslednja
Stran 1 od 2

 
Pojdi na:  
Ne, ne moreš dodajati novih tem v tem forumu
Ne, ne moreš odgovarjati na teme v tem forumu
Ne, ne moreš urejati svojih prispevkov v tem forumu
Ne, ne moreš brisati svojih prispevkov v tem forumu
Ne ne moreš glasovati v anketi v tem forumu
Ne, ne moreš pripeti datotek v tem forumu
Ne, ne moreš povleči datotek v tem forumu

Uptime: 47 dni


Powered by phpBB © 2001, 2005 phpBB Group