HobbyElectro

Petrescu Cristian . Un produs Blogger.

joi, 26 decembrie 2013

CATE CEVA DESPRE TRANSCIEVER-UL NRF24L01

0 comentarii | Read more...

   Lucrand pentru proiectul meu de licenta am dat "nas in nas" cu transciever-ul bazat pe circuitul integrat NRF24L01 produs de firma NORDIC SEMICONDUCTOR. Este un device foarte ieftin, eu am cumparat 3 bucati la pretul 12 RON bucata. Deocamdata sunt faza testelor dar am considerat ca ar fi util sa impartasesc cate ceva despre aceasta jucarie.  Recomand citirea posturilor anterioare privind protocolul SPI.

     HERE WE GO !!


1.DETALII TEHNICE:

  1. MODUL DE CONECTARE AL PINILOR SI COMENZILE SPECIFICE


Transcieverul NRF 24L01 produs de firma NORDIC SEMICONDUCTOR foloseste pentru a comunica cu exteriorul protocolul SPI. Din aceasta cauza pinii descrisi in cele ce urmeaza sunt caracteristici acestui protocol.

  • MOSI – master out (master=uC) slave in (transceiver)
  • MISO – master in slave out
  • CLK - semnalul de ceas dupa care se efectueaza transmisia
  • CSN - pin utilizat ori de cate ori se comunica cu transcieverul (ACTIVE LOW)
  • IRQ - interrupt request, atentioneaza ca in interiorul transcieverului s-a intamplat ceva
  • CE - chip enable, se utilizeaza pentru controlul transmisiei (RX: CE=HIGH, TX: CE=LOW)
  • VCC - pinul de alimentare 3.3V
  • GND


Din cele patru moduri de transmitere a informatiei prin protocolul SPI NRF 24L01 foloseste  modul "0"  (CPHA=0, CPOL=0). Din acest motiv modulul SPI din iteriorul uC trebuie setat in acest mod.

Pentru a citii sau scrie date in registrii interni ai transcieverului se folosesc o serie de comenzi prezentate in urmatorul tabel:




  • R_REGISTER se utilizeaza pentru a citii datele din interiorul unui SFR al transcieverului. Modul de utilizare este urmatorul: in locul caracterelor "A" se introduce adresa pe care dorim sa o citim. Aceata valoare se transmite prin SPI transcieverului. In acest moment NRF-ul stie ca trebuie sa citeasca o anumita adresa. Pentru a "scoate" valoarea acesteia se mai transmite un numar de bytes egali cu latimea registrului care trebuie citit. De exemplu daca dorim sa citim un registru care are latimea de 1 byte si este localizat la adresa 01h algoritmul este urmatorul:
  1. CSN se face LOW;
  2. Se trimite prin SPI instructiunea R_REGISTER care este de forma: 0b00000001;
  3. Desi nu ne intereseaza este nevoie sa citim ceea ce ne trimite NRF-ul.
  4. Se trimite un byte oarecare ( de obicei NOP) iar ceea ce primim inapoi este chiar valoarea adresei care ne intereseaza.

  • W_REGISTER se utilizeaza pentru a scrie o anumita valoare intr-un registru intern al NRF-ului. Modul de utilizare este urmatorul: in locul caracterelor "A" se introduce adresa pe care dorim sa o citim. Aceata valoare se transmite prin SPI transcieverului. In acest moment NRF-ul stie ca trebuie sa scrie la o anumita adresa. Pentru a "scrie" valoarea acesteia se mai transmite un numar de bytes egali cu latimea registrului care trebuie citit. De exemplu daca dorim sa citim un registru care are latimea de 1 byte si este localizat la adresa 03h algoritmul este urmatorul:





  1. CSN se face LOW;
  2. Se trimite prin SPI instructiunea W_REGISTER care este de forma :0b00100011;
  3. Desi nu ne intereseaza citim ceea ce ne trimite in aceasta faza NRF-ul;
  4. Trimitem pe SPI un byte care va fi scris la adresa 03h;
  5. Citim din nou ceea ce primim.

Inainte de a explica R_RX_PAYLOAD si W_TX_PAYLOAD ar trebui discutat conceptul de "payload". Payload-ul nu este altceva decat denumirea data de producator pentru datele primite si transmise.
Atat pe partea de transmise (TX) cat si pe cea de receptie (RX) exista cate un registru de tip FIFO (first in first out) structurat pe cate trei nivele. Latimea acestor nivele poate fi de la 1 la 32 bytes, in functie de cum se seteaza payload-ul. Sa luam de exemplu RX FIFO si sa consideram ca in modul de comunicare intre doua transceivere de tip NRF 24L01 datele au fost setate sa aiba o latime de 5 bytes .
Emitatorul (TX) trimte primul payload acesta este primit de catre receptor (RX) si stocat in primul nivel al RX FIFO al acestuia. In acest moment mai sunt libere inca doua nivele. Receptorul poate fi setat sa citeasca primul payload sau mai poate astepata pana RX FIFO se umple (inca doua payload-uri) si de abia dupa aceea sa citeasca succesiv datele primite.

  • R_RX_PAYLOAD se utilizaza pentru a citii datele primite. Dupa cum am vazut atunci cand transcieverul este in modul RX pinul CE este setat HIGH. Dupa ce am primit maximum 3 payload-uri (RX FIFO este plin) si minim 1, CE se setaza LOW si se trece la executarea urmatorului algoritm:
  1. Se trimite prin SPI 0b01100001;
  2. Desi nu ne intereseaza citim ce ne trimite NRF-ul;
  3. Se trimite un byte oarecare prin SPI NRF-ului iar ceea ce citim inapoi este de fapt byte-ul zero al payload-ului. Se continua trimiterea si citirea de bytes pana cand a fost atinsa latimea la care a fost setat payload-ul.

  • W_TX_PAYLOAD se utilizeaza pentru a scrie datele in TX FIFO, adica datele care vor fi transmise. In modul TX pinul CE este setat LOW. Se executa urmatorul algoritm:
  1. Se trimite prin SPI 0b10100000;
  2. Desi nu ne intereseaza citim ceea ce ne trimite NRF-ul;
  3. Se incarca nivelele sau , daca se doreste, doar primul nivel al TX FIFO cu un numar de bytes egal cu latimea payload-ului. Acest lucru se face trimitand succesiv prin SPI numarul dorit de bytes avand grija sa citim in acelasi timp ceea ce ne trimite tranceiver-ul.
  4. Dupa ce au fost incarcate datele CE se seteaza HIGH pentru o perioda de minim 10 uS.
  • FLUSH_TX si FLUSH_RX sunt folosite pentru a sterge datele existente in RX si TX FIFO.
  • REUSE_TX_PL se utilizeaza pentru a transmite in mod constant aceleasi date incarcate in TX FIFO.
  • NOP dupa cum ii zice si numele nu executa nimic si este folosit pentru a citii starea registrilor, de exemplu registrul STATUS.

    1. DESCRIEREA REGISTRILOR INTERNI


00h . REGISTRUL CONFIG


  • BIT0 – PRIM_RX seteaza modul de operare : 1 = RX , 0=TX;
  • BIT1 – PWR_UP porneste sau opreste transciever-ul 1=ON, 0=OFF;
  • BIT2 – CRCO modul de codare a CRC-ului 1 = 2 bytes, 0 = 1byte;
  • BIT3 – EN_CRC seteaza daca CRC-ul este activ sau nu;
  • BIT4 – MASK_MAX_RT seteaza daca se utilizeaza ca intrerupere depasirea numarului maxim de retransmiteri a datelor 1=se utilizeaza si se genereaza o intrerupere pe pinul IRQ, 0 = nu se utilizeaza.
  • BIT5 – MASK_TX_DS seteaza daca se utilizeaza ca intrerupere trimiterea cu succes a unui pachet 1 = se genereaza o intrerupere pe pinul IRQ, 0 = nu se utilizeaza;
  • BIT6 – MASK_RX_DR seteaza daca se utilizeaza ca intrerupere primirea cu succes a unui pachet 1 = se genereaza o intrerupere pe pinul IRQ, 0 = nu se utilizeaza;
  • BIT7 – NU SE UTILIZEAZA

01h . REGISTRUL EN_AA (ENHANCED SHOCKBURST)



Inainte de a vorbi despre acest registru este necesar sa discutam putin despre conceptul "data pipe". Sa dam urmatorul exemplu:
Sa presupunem ca utilizam 3 transcievere (T1, T2, T3 ) astfel: Primul dintre ele primeste datele de la celelalte doua si in functie de ceea ce primeste trimite date celor doua transcievere inapoi.


Figura 1 : Data pipes si adresele

Cum frecventa este fixa cum se poate afla cine a trimis primului transciever (T1) date ? Simplu. Prin "data pipes". Fiecare NRF24L01, in modul RX, dispune 6 astfel de "data pipes". In functie de cum se seteaza (vom vedea mai tarziu in care registru) payload-ul este atasat uneia dintre ele. De asemenea trebuie aleasa si o adresa unica pentru fiecare data pipe. Privind "Figura 1" observam ca atunci cand T1 comunica cu T2 datele sosesc la adresa A1 iar cand comunica cu T3 datele sosesc la adresa A2. Cand T1 trimite date catre T2 adresa sa TX trebuie schimbata cu adresa de RX a data pipe 0 a acestuia adica A1 si cu A2 cand trimite catre T2.

Revenind la registrul de mai sus acesta are rolul de a activa "auto acknwledgement" pentru fiecare data pipe folosita. Auto acknwledgement inseamna autoconfirmarea primirii sau transmiterii cu succes a datelor.

02h . REGISTRUL EN_RXADDR




Acest registru are rolul de a activa sau dezactiva data pipes folosite. Revenind la exemplul de mai sus putem spune ca atunci ca deoarece T1 comunica cu alte doua transcievere atunci sunt necesare doar doua data pipes, care se activeaza scriind "1" bitului aferent acesteia.
03h . REGISTRUL SETUP_AW


In acest registru setand bitii 1:0 se fixeaza latimea adresei atat in modul RX cat si in TX:
  • '00' – nu se poate alege;
  • '01' – latimea este de 3 bytes;
  • '10' – latimea este de 4 bytes;
  • '11' – latimea este de 5 bytes.
Este de recomandat sa se aleaga o latime a adresei de 5 bytes deorece exista sanse mai mici de interferenta cu alte dispozitive care functioneaza in banda de 2.4 Ghz.


04h . REGISTRUL SETUP_RETR



Exista sansa ca nu intotdeauna datele sa ajunga "din prima" la receptor. Acest registru seteaza intervalul de timp la care se va face retransmisia si numarul de retransmisii. Acesta din urma nu poate fi mai mare de 15.

05h . REGISTRUL RF_CH



In acest registru este setata frecventa de operare a transcieverului utilizand in acest scop bitii 6:0. Numarul obtinut combinand acesti biti reprezinta numarul canalului pe care opereaza transcieverul intre fiecare canal existand un ecart de 1Mhz. Se poate deduce astfel ca exista 127 de canale frecventa minima fiind 2.4 Ghz iar cea maxima 2.527 (2.4+0.127) Ghz.

06h . REGISTRUL RF_SETUP



In acest registru se seteaza puterea transmisei RF_PWR (bitii 2:1) si viteaza de transmisie RF_DR (bitul 3).

07h . REGISTRUL STATUS




STATUS este unul dintre cei mai importanti registrii deoarece confera informatii despre starea actuala a transciever-ului. Sa luam pe rand fiecare bit:

  • BIT0 – TX_FULL : semnalizeaza daca mai sunt locatii libere in TX FIFO. 1 = TX FIFO este plin; 0 = mai exista locatii libere in TX FIFO
  • BIT 3:1 – RX_P_NO : combinatia dintre acesti biti semnalizeaza la care din cele 6 data pipe au fost primite date. Revenind la exmplul cu cele 3 trancievere, pentru a sti de la cine a primit T1 date se verifica acesti biti. In cazul lui T2 si T3 valoarea acestor biti va fi '000' atunci cand se primeste ceva deoarece se utilizeaza numai data pipe 0
  • BIT 4 – MAX_RT : flag de intrerupere atunci cand numarul maxim de retransmisii a fost atins. Ca o ciudatenie, pentru a sterge acest flag trebuie scris bitul tot cu valoarea 1 .
  • BIT5 – TX_DS : flag de intrerupere care semnalizeaza daca pachetul a fost trimis cu succes. Daca AUTO_ACK este activat atunci acest bit va fi setat numai daca a fost facuta confirmarea primirii cu succes a pachetului.
  • BIT6 – RX_DS : flag de intrerupere care semnalizeaza daca pachetul a fost primit cu succes.


08h . REGISTRUL OBSERVE_TX


  • BIT 3:0 – ARC_CNT : numara de cate ori au fost retransmise pachetele pentru o anumita data pipe. Daca se transmite un pachet nou numaratoarea se reseteaza.
  • BIT 7:4 – PLOS_CNT : numara de cate ori a fost a fost retransmis un pachet pentru numarul maxim de retransmisii setat in registrul SETUP_RETR prin bitii 3:0 (ARC). De exemplu daca se setaeza ARC=1111 adica maximum posibil (15) si daca numarul de retransmisii a depasit aceasta valoare atunci PLOS_CNT se incrementeaza cu +1. Numarul maxim inregistrat este 15. Dupa aceasta valoare nu se mai inrcrementeza pana la reset.

Acest registru are rolul de a ne ajuta sa ne dam seama daca calitatea semnalului este buna in zona in care dorim sa lucram. Daca se pierd multe pachete atunci fie distanta este prea mare fie ar trebui schimbata frecventa in registrul RF_CH.

09h . REGISTRUL CD (carrier detect)



Un singur bit se foloseste in acest registru : bitul 0. Citind acest bit se poate verifica daca cineva sau "ceva" transmite pe frecventa NRF-ului.

In registrii 0Ah : 0Fh se seteaza adresele data pipes utilizate.



Latimea maxima a adresei fiecarei data pipe este de 5 bytes, aceasta setandu-se in registrul SETUP_AW. Pentru RX_ADDR_P0 si RX_ADDR_P1 aceasta adresa poate fi orice combinatie de maxim 5 bytes. Pentru RX_ADDR_P2, RX_ADDR_P3, RX_ADDR_P4 si RX_ADDR_P5 primii bytes sunt identici cu cei ai RX_ADDR_P1 iar ultimul byte se incrementeaza cu +1 asa cum este aratat in tabel.

Revenind la exemplul cu cele 3 transcievere (T1, T2, T3) in acesti registrii se vor seta urmatoarele adrese:

  • pentru T1 adresa RX_ADDR_P0 = A1 ; RX_ADDR_P1=A2;
  • pentru T2 adresa RX_ADDR_P0 este A1;
  • pentru T3 adresa RX_ADDR_P0 este A2,

unde A1, A2, A3 sunt adrese cu o latime de la 1 la 5 bytes.

10h . REGISTRUL TX_ADDR



In acest registru este setata adresa de transmise a transciever-ului. Latimea acesteia fiind setata in registrul SETUP_AW.


Pentru cele trei transcievere aceasta adresa se seteaza in modul urmator:

  • pentru T1 daca comunica cu T2 TX_ADDR=A1 iar daca comunica cu T3 este egala cu A2;
  • pentru T2 TX_ADDR=A1;
  • pentru T3 TX_ADDR=A2,

unde A1, A2, A3 sunt adrese cu o latime de la 1 la 5 bytes.


In registrii 011h : 016h se seteaza latimea payload-ului pentru fiecare data pipe:




Pentru a utiliza payload-ul trebuie seatata macar o latime de 1 byte. Apeland din nou la exemplul cu cele 3 transcievere si presupunand ca T1 schimba cu T2 date care au latimea de 2 bytes si cu T3 de 5 bytes se pot face setarile:

  • pentru T1: RX_PW_P0 = 000010, RX_PW_P1 = 000101;
  • pentru T2 : RX_PW_P0 = 000010 ;
  • pentru T3: RX_PW_P0 = 000101 .

17h . REGISTRUL FIFO_STATUS



Acest registru ofera informatiile necesare pentru aflarea starii celor doi registrii: RX_FIFO si TX_FIFO.

     Cam asta ar fi in partea de descriere a NRF 24L01. Voi incerca sa postez in cel mai scurt timp un mini algoritm de configurare.



luni, 23 decembrie 2013

LEDURI, BUTOANE SI XC8 (Partea III)

0 comentarii | Read more...

Dupa cum am zis in postarea trecuta voi incerca sa atasez fiecarui buton cate o functie care sa aprinda ledurile conectate la PORTB intr-un anumit mod.

     In postarea de astazi am atsat butoanelor 1,2,3,4 cate o functie astfel:


  1. Butonul 1 : aprinde pe rand cate un led ("shifteaza" la stanga PORTB de la valoarea 1 la 128 ) ;
  2. Butonul 2 : aprinde pe rand cate un led ("shifteaza" la dreapta PORTB de la valoarea 128 la 1 ) ;
  3. Butonul 3 : combina cele doua functii de mai sus ;
  4. Butonul 4 : aprinde doua leduri si shifteaza pe rand la stanga si la drepta PORTB.
     Programul inital se modifca, fiind adaugate pe langa functiile asociate fiecarui buton inca doua functii, sa zicem ceva mai speciale. Sa vedem intai codul modifcat si apoi sa comentam putin aspectele mai interesante.





     In functia main() nu se modifica nimic iar in scan() in loc sa aprindem ledurile direct pe PORTB atsasam fiecarei apsari de buton functia aferenta. Dupa cum am zis in postarea anterioara apasarea unei taste se verifica prin operatia XOR "char button=PORTD^shifter" . Daca rezultatul nu este "0" atunci inseamna ca o tasta a fost apasata. Intre timp, daca utilizatorul este foarte rapid, exista posibilitatea ca PORTD sa revina la valoarea initiala, asa ca este necesara reconstructia valorii PORTD din momentul apsarii tastei.

      Acest lucru se realizeaza prin utilizarea operatorului OR in operatia "char a=button|shifter". Acum ca stim valoarea apelam functia asociata butonului. Aceasata ia ca parametru valoare "a"  adica valoarea lui PORTD din momentul apasarii butonului. De ce? Pentru ca asa cum vom vedea mai departe la inca o apasare a aceluiasi buton functia asociata acestuia isi va opri executia.

     In cele ce urmeaza voi explica doar modul in care functioneaza functia  "keypad1(unsigned char a)".
     Dupa apasarea butonnului 1 programul va incerca sa execute aceasta functie astfel:


  • va apela functia "debounce (a)" care practic va tine programul pe loc atat timp cat butonul 1 continua sa fie apasat.
  • apoi face variabila globala flag egala cu 1. Aceasta variabila este verificata in timpul executiei functiei pentru a ne asigura ca butonul 1 nu a fost apasat din nou, fapt care duce la intreruperea excutiei functiei.
  • PORTB ia valoarea 1 si se apeleaza functia "delay_500_milli(unsigned char a)" .
      Aceasta functie nu face altceva decat sa asigure un delay de 0.5 s si sa setezeze variabiala globala flag 0 daca a fost apasat acelasi buton. Delay-ul este obtinut cu ajutorul TIMER0. Acesta este setat sa asigure un delay de ~ 25 ms pana cand are loc overflow-ul acestuia fapt care va duce ca flagul de intrerupere "INTCONbits.T0IF" sa fie setat 1. Asadar pentru a obtine un delay de 500 de ms sunt necesare 20 de iteratii. Dupa sfaristul fiecarei iteratii, adica dupa 25 ms, se verifica starea PORTD. Daca acesta revine la valoarea din momentul primei apasari a butonului atunci variabiala "flag este setata 1", fapt care va duce la intreruprea executiei  functiei keypad1(a). In acest moment programul se intoarce inapoi in functia scan() si va detecta alte apasari de taste.

     Cam asta ar fi.  Iar in cel mai scurt timp voi incerca sa postez si un filmulet cu executia programului.

joi, 19 decembrie 2013

MATRICE BUTOANE SI LEDURI

0 comentarii | Read more...

    Dupa cum am spus ca voi face, am reusit sa incarc si un filmulet cu butoanele si leduriele.


Iata-l:




miercuri, 18 decembrie 2013

LEDURI, BUTOANE SI XC8 (Partea II)

0 comentarii | Read more...

     In cea de-a doua parte a prezentarii vom pune picul la treaba. Sa incepem prin a prezenta schema de ansamblu a proiectului:



     Dupa cum se vede nu este nimic special. PORTB este utilizat pentru a aprinde si stinge ledurile care reprezinta numarul scris in binar al butonului  care a fost apsat. Mecanismul, dupa cum am spus si in prima parte, este unul destul de simplu:
  •  schimba foarte repede starea bitilor RD4,RD5,RD6,RD7 (definiti ca iesiri) 
  • scaneaza foarte repede bitii RD0,RD1,RD2,RD3 (definiti ca intrari) si vezi daca isi schimba starea
  • daca starea se schimba actioneaza in consecinta.


     Acum haideti sa vedem codul si sa comentam aspectele mai importante.



    Nu voi insista asupra configurarii picului, comentariile din cod vorbesc de la sine. Cea mai importanta variabila din intreg codul este variabila globala "shifter". Dupa cum se vede a fost scrisa in binar pentru a putea intelege mai bine rolul acesteia. Practic aceasta variabila este un fel de imagine a PORTD. Voi explica mai pe indelete rolul ei ceva mai tarziu. 

Mai departe in main () setam PORTB ca fiind output (TRISB=0) iar PORTD jumatate ca input si jumatate ca output (TRISD=0b00001111).  Apoi se seteaza registrul ADCON1 pentru a folosii toti pinii ca intrari sau iesiri digitale. 

     In momentul in care se schimba starea logica a bitilor 4-7 din PORTD este necesar ca fiecare pin dintre cei mentionati sa "stea" o perioada de timp "HIGH", perioada in care programul verifica daca a fost sau  nu apasat un buton. 
    Acest lucru se realizeaza cu ajutorul unui timer, mai precis Timer1. Timer-ul in cauza incrementeza valoarea lui TMR1L cu +1 dupa fiecare instructiune efectuata. Cand TMR1L da pe-afara (adica depaseste valoarea de 255 sau 0xFF) se adauga +1 la TMR1H. Cand si cel din urma depaseste 255 atunci automat este setat bitul TMR1IF din registrul PIR1. 

    Din cele afirmate mai sus rezulta ca se numara practic un numar de 65535 instructiuni. Dar cat dureaza o instructiune? Dupa cum se vede in cod am folosit un cristal de quartz de 8MHz. Asta inseamna ca o perioada tine 1/8000000 s sau 0.125 us. Cum picul are nevoie de de 4 astfel de perioade pentru a executa o instructiune rezulta ca timpul necesar este de 0.125x4=0.5us. Revenind la TIMER1 vedem ca timpul necesar pentru ca TMR1IF din registrul PIR1 sa devina "1" este : 0.5 x 65535 = 32.7675 ms. Evident ca se poate seta registrul T1CON in asa fel incat sa se incrementeze TMR1L la mai mult de  o instructiune. Acest lucru se face  setand bitii T1CKPS0  si T1CKPS1 confrom datasheet-ului. Pentru scopul de fata un prescaler de 1:1 este suficient.

     Mai departe se intra in bucla infinita "while(1)". Primul lucru care se executa aici si care de fapt este inima intregului program este apelarea functiei "scan ()" .
      Primul lucru care se executa in "scan ()" este atribuirea lui PORTD a variabilei shifter. In acest moment PORTD are bitul 4 setat ca "HIGH" (presupunand ca shifter este 0b00010000 ) . Din acest moment incep sa se petreaca urmatoarele evenimente:
  1. Se porneste TIMER1
  2. Pentru un interval de timp de ~33ms (atat timp cat TMR1IF=0) se verifica urmatoarele:
  • daca a fost apasat un buton valoarea PORTD se schimba, acest lucru este verificat facand operatia "XOR" sau "SAU EXCLUSIV" intre noua valoare a PORTD si valoarea originala shifter.
  • daca a fost detectata o schimbare (variabila button nu este egala cu 0) atunci, deoarece este posibil ca butonul sa fi fost eliberat, se reconstruieste valoarea lui PORTD din momentul apasarii butonului facand operatia logica "SAU" intre shifter si button.
                      iata un exemplu : sa zicem ca era randul lui RD4 sa fie "HIGH" si a fost apasat butonul "1" 

                      shifter=0b00010000 ; PORTD=0b00010001;
                      button=shifter XOR PORTD
                      button=0b00000001
                      intre timp butonul 1 a fost eliberat astfel ca PORTD este egal din nou cu shifter
                      a=shifter OR button 
                      a=0b00010001, (17)  adica valoarea lui PORTD din momentul apasarii butonului

  • in functie de aceasta valoare se aprind ledurile din PORTB.    

     Inapoi in main () si in while(1). Dupa ce se iese din functia scan() trebuie verificat daca nu cumva shifter are valoarea 128 (adica  RD7 a fost "HIGH"). Daca da atunci se revine la valoarea de baza a lui shifter iar daca nu se aplica functia shift left asupra aceleiasi variabile. Ultimul lucru care trebuie facut este sa resetam valorile TMR1H , TMR1L si flagul TMR1IF accesand functia reset_timer().

     Cam asta ar fi. In cel mai scurt timp voi incerca sa postez si un filmulet cu dovada ca functioneaza. 
     In alta ordine de idei incepand cu posturile viitoare vom  atasa fiecarui buton cate o functie care va face diverse giumbuslucuri cu leduri si alte jucarii.








sâmbătă, 14 decembrie 2013

LEDURI, BUTOANE, SI XC8 (Partea I)

0 comentarii | Read more...


DACA LEDURI SI BUTOANE NU "E" NIMIC NU "E"......


     Ledul si butonul ... totul incepe cu unul din ele sau,  de ce nu, cu amandoua. Ma gandesc ca daca peste vreo 50 de ani s-ar inventa cine stie ce bazadaganie cu care vom putea controla diverse lucruri cu ajutorul mintii in perioada de training cu singuranta vom apasa butoane si vom aprinde leduri.

     Treaba cu butoanele este atat de bine infipta in mentalul colectiv ca pana si la telefoanele mobile sau la tabletele cu "touch screen" cand apasam pe ecran in diverse aplicatii spunem ca apasam butoane, ce-i drept virtuale. Vedeti ? Nimic nu se pierde - totul se transforma.

    Dupa ce in postarea trecuta am prezentat dev-boardul de Aptinex m-am gandit ca ar fi momentul sa incep sa o pun la treaba, prezentand ceva programele facute pentru PIC 16F877A. In mare voi incerca ca in fiecare postare sa prezint cate un modul cu ajutorul caruia sa controlez cate un periferic (sau mai multe) aflate pe placa.
   Cum toata lumea incepe cu un led sau un buton am zis ca nici eu sa nu fac rabat de le regula, doar ca fiind mai cu mot, eu voi lucra in postul de azi cu 16 butoane si 8 leduri. Laser frate!
    Ca si compilator voi folosi pentru programele expuse aici XC8 de la Microchip. In varianta pentru uC din seria de 8 biti nu vine cu nici un fel de librarie pentru modulele interne ale pic-urilor din seria 16, lucru destul de aiurea pentru cei care sunt obisnuti cu compilatoare "siliconate" cu tot felul de functii. Partea buna este ca utilizand acest compilator reusiti sa deventi destul de intimi cu structura interna a uC,  lucru esential pentru cineva care doreste sa treaca de la hobby la partea profesionala.

   Compilatorul necesita IDE-ul de la Microchip (Mplab X IDE) care este gratis si se decarca de aici. XC8-ul se decarca si el la randul lui de aici. Urmati pasii din instalare iar pentru a crea un proiect nou se procedeaza in modul urmator:

    Se da click pe "new project" iar in prima fereastra se alege "Microchip Embedded" si "Standalone Project".

New Project

     Mai departe, in urmatoarea fereastra, se alege familia de microntrollere si uC pe care doriti sa il utilizati. In cazul de fata se va alege PIC 16F877A.


Alegere Microcontroller

     In urmatoarea fereastra sunt prezenate optiunile pentru debugging, eu am ales ca mod de debugg simulatorul inclus in Mplab X.

Alegerea modului de debugg

     In fine, dati un nume proiectului si ati terminat cu partea de creare a unui proiect nou. Pentru a adauga fisierul "main.c" in proiect dati click-dreapta pe "Source Files" si alegeti  "C Main File". La "File Name"
scrieti "main" (fara ghilimele). Mplab -ul il va salva implicit acolo unde ati creat proiectul.

Crearea fisierului "main.c"




     Inca putin si e gata. In aceasta faza trebuie setati bitii de configurare. Pentru a ne usura munca Mplab-ul ne da posibilitatea sa ii setam usor, astfel: Click "Window", "PIC Memory Views", "Configuration Bits".
     In partea de jos a programului se va deschide un meniu in care putem alege configuratia dorita.


Deschidere "Configuration Bits"


     Dupa ce i-ati setat (ceea ce modificati va aparea cu rosu) click pe butonul magic "Generate Source Code to Output" si acum ii puteti copia in fisierul main.

Generate Source Code to Output

   Gata cu setarile. Acum sa vorbim putin despre proiectul in sine.  Ceea ce vreau sa fac este sa folosesc toate cele 16 butoane pe care placa mi le pune la dispozitie, impreuna cu 8 leduri. Ideea este ca, numerotand butoanele de la 1 la 16, ori de cate ori se apasa un buton ledurile se aprind afisand practic in binar numarul butonului. Cele 16 butoane sunt legate la PORTD (4 pini sunt stati ca input RD0-RD3 si 4 ca output RD4-RD7) iar ledurile la PORTB. La prima vedere nu pare mare lucru, cum de fapt nici nu este. Singura problema este cum sa controlez 16 butoane cu doar 8 pini.  
    Dupa cum am spus 4 din pinii PORTD sunt setati ca input si 4 ca output. Cei de output isi schimba starea logica  (0 sau 1) la un interval regulat de timp setat printr-un timer. Cei de input sunt legati prin intermediul unei rezistente la masa. Cand este apasat un buton datorita faptului ca, indiferent cat de rapid l-am apasa, o perioda de timp contactul lui din interior ramane inchis si, daca, schimbarea starii pinilor de output se face suficient de rapid, la un moment dat pinul de input primeste 5V de la cel de output. Din combinatia celor doi pini se poate deduce butonul care a fost apasat. Si, dupa cum spun mereu, cum o poza face cat 1000 de cuvinte sa privim urmatoarea diagrama:

MATRICE DE BUTOANE
     Asadar RD0-RD3 sunt pinii de intrare care, daca butoanele nu sunt apsate sunt pusi la masa prin intermediul rezistentelor de "pull down". Daca, sa zicem, se inchide contactul butonului 1si in acel moment starea logica a lui RD4 este "1" atunci si RD0  va capata aceasta stare si, implicit tot portul D va avea o anumita valoare (vom vedea in cod). Ati prins ideea? Daca da atunci incercati sa va imaginati o alta combinatie.


sâmbătă, 7 decembrie 2013

APTINEX PIC DEV. BOARD pentru uC cu 40 de pini

1 comentarii | Read more...

     De ceva vreme, satul fiind de tot felul de module si placute conectate pe breadboard, cautam o placa de dezvoltare pentru uC cu cat mai multe si felurite module. Am incercat sa construiesc si eu cateva dar cu mijloacele specifice unui amator mi s-a parut aproape imposibil sa reduc marimea placutelor la o scara acceptabila. Vroiam sa gasesc ceva care sa fie compact dar totodata sa imi confere libertate in modul de conectare a modulelor la uC. Cautand si tot cautand am dat in final peste mai sus numita placa. 
     Placa este produsa de firma Aptinex din Sri Lanka si ofera cam tot ceea ce este nevoie pentru ca un incepator sa-si dezvolte aptitudinile in programarea uC-lor. Iar pretul... (asta e partea mea favorita) pretul este unul foarte mic pentru dotarile de care dispune. Sa nu o mai lungesc si sa va tin in suspans, placa a costat DOAR 120 ron.  

     Pentru inceput voi trece in revista principalele module de care dispune urmand apoi sa le disec pe fiecare in parte:

  • 1 bucata socket ZIF cu 40 pini
  • 4 bucati display cu 7 digiti
  • 1 bucata buzzer
  • 1 bucata senzor IR (TSOP 1830)
  • 1 bucata real time clock (DS1307)
  • 1 bucata releu SPDT cu tranzistorul aferent de comanda
  • 8 leduri cu rezistente de limitare a curentului (3k3)
  • 2 bucati potentiometre (numai bune pentru a testa convertorul analog-digital)
  • 4 bucati mosfeturi (cu nivel logic de comanda ) impreuna cu diodele de protectie aferente (motoare!!)
  • 16 butoane multiplexate 
  • 1 interfata seriala (max 3232)
  • 1 bucata 16x2 LCD cu potentiometru pentru reglarea luminozitatii
  • pini pentru ICSP
      Asadar dupa cum se poate observa este o placa destul de potenta ce poate usura munca oricarui amator dar, care,  mai cu seama are avantajul de a salva   o groaza de spatiu tinand toate modulele grupate intr-un mod compact. Fiecare modul se conecteaza la pinii uC -ului prin fire monofilare normale (sau daca exista in dotare de breadboard - tata-tata). Pentru montaje complicate, cand se folosesc concomitent mai multe module, este posibil ca placa sa arate ca parul lui Bob Marley dar, pana la urma, chestia asta se intampla si in lucrul breadboard-ul clasic.
     Pe langa toate delicatesele enumerate mai sus in pachet se mai gasesc si 4 cristale de quartz (4, 8, 16, 20 MHz) pentru ca da, placa dispune de un soclu in care se pot monta si schimba cristalele in fuctie de necesitati. Ca sa nu uit trebuie sa va atrag inca de pe acum atentia asupra unui fapt: quartz-urile vin cu pini lungi asa ca inainte de a le monta in soclu este indicat sa taiati pinii cat mai scurt pentru ca altfel exista posibilitatea ca in timpul functionarii sa apara probleme. Pe langa cristale mai exista si o baterie CR2032 necesara pentru alimentrea RTC-ului.     
     Si cum gargara multa saracia omului, iata placa asa dupa cum o vede camera umilului meu telefon :

PLACA DE DEZVOLTARE APTINEX 40 PINI
        Asadar am vazut poza iar inainte de a incepe sa disecam fiecare bloc in parte, pentru ca sunt "baiat bun", voi atasa si schema elctronica in format pdf aici.

        Si acum sa vedem ce se afla inauntru:

1. ALIMENATREA
     
    
    Nimic special, poate doar faptul ca exista un buton cu retinere cu care se poate alege tensiunea de alimenatre fie de la USB fie de la alimentatorul de 9 -12 V. Se mai poate obesrva ca   pinii de date ce pleaca de la USB pot fi accesati separat. 
     
2. MICRONTROLLER-UL


      Nu va speriati !! In realitate pe placa totul este ordonat, pinii fiind pusi in ordine. 
    Aici avem butonul clasic de RESET fara condensator si o chestie care mie personal mi s-a parut foarte interesanta: se observa ca la PORTB,  pinii 6 si 7 ( PGC si PGD ) nu sunt legati direct la conectori. In cazul in care utilizati ICSP si nu aveti nevoie de cei doi pini in proiect nu este nici o problema, insa daca doriti sa ii folositi in montaj  acestia pot fi izolati in momentul programarii prin intermediul a doi jump-eri.
      Se mai observa in poza si LCD-ul  si cele doua potentiometre folosite la conversia analog-digital.

3. LEDURI, ICSP, PULL-UP, DOWN, ALIMENTARE PERIFERICE

  
     Interesant aici este faptul ca placa ne ofera posibiliatea de a alimenata alte bazdaganii ce nu se regasesc printre cele enumerate mai sus direct la 5V prin conectorii SL9 si SL10, iar pentru diversele cazuri in care avem nevoie de rezistente de PULL UP sau DOWN acestea pot fi alese din cele 8 disponibile fiecare dintre ele avand o valoare de 33K. Personal am folosit alimenatrea la 5V cu un LM 1117-3.3V pentru a alimenta  un transceiver NRF24L01.

4. DISPLAY-URILE CU DIGITI


     Dupa cum se obesrva exista un singur conector la care sunt legati in comun cei 7 digiti ai fiecarui modul. Selectia  se face cu ajutorul tranzistoarelor care au legat in colector pinul CC (common cathode). Afisarea virgulei se face accesand separat pinul DP al fiecarui modul.

5. RELEUL SI MOSFETURILE


     Daca vreti sa comandati motoare sau alte sarcini cu consum substantial atunci aveti la dispozitie 4 MOS-FET-uri protejate de diode. Se poate selecta tensiunea de alimentare a sarcinii  utilizand un jumper. In prima pozitie ne permite alimentarea utilizand alimentatorul extern, iar in cea de-a doua pozitie o sursa de alimentare independenta (aceasta se leaga la bornele X7) . Sarcinile se inseriaza cu sursele MOS-urilor si cu "+-ul" sursei de alimentare ( bornele X3, X4, X5, X6 ). 
     In ceea ce priveste releul acesta este comandat de catre un tranzistor iar pozitia contactelor sale este marcata pe placa. De fapt , asa ca o simpla paranteza, totul este marcat foarte explicit pe placa.

6. BUTOANELE.


     Aici nu este mare lucru de spus, configurarea se poate face in mai multe moduri in functie de cerintele aplicatiei.

     CONCLUZIE

     Una peste alta jucaria prezentata mai sus isi merita cu prisosinta toti banii. Va mai trebuie un alimentator de 9-12V la minim 1A, ceva cabluri si sunteti gata sa ii dati bataie (asta daca aveti deja programatorul). 


duminică, 1 decembrie 2013

Despre protoculul SPI..... (Partea 2)

0 comentarii | Read more...
        Am vazut in prima parte a prezentarii faptul ca lucrurile "se misca in cerc" si, contrar intelesului, in final chiar se intampla ceva (se transmite informatie). Daca lucrurile nu pareau complicate si totul era frumos (bitii se bateau cap in cap pe ritmul impus de semnalul de ceas ) cei care au dezvoltat protocolul s-au gandit ca ar fi cazul sa le complice, introducand doua concepte : CLOCK POLARITY si CLOCK PHASE. 

        Ce Dumnezeu or fi si astea ? Personal mie mi-au scos peri albi si nu pentru ca ar fi cine stie ce taina de nepatruns ci tocmai datorita faptului pe care il subliniam in prima parte : FIECARE PRODUCATOR IMPLEMENTEAZA PROTOCLUL UTILIZAND DENUMIRI PROPRII. 

         Pentru a intelege exact cine cu ce se mananca este de mare ajutor urmatoarea imagine:



POZA 1: Faza si polaritate


      Stim deja ca pentru a initia transmisia este necesar ca pinul SS sa fie adus LOW. Apoi mai stim ca este necesar un semnal de ceas (SCK).
    Daca ati cautat cate ceva pe net despre acest protocol probabil ca v-ati intalnit cu termenul IDLE CLOCK. Chestiuta asta inseamna de fapt nivelul logic al semnalului de ceas in momentul in care SS este adus LOW. Cum orice bit nu poate lua decat doua valori 0 sau 1 asta inseamna ca  la randul lui semnalul de ceas nu poate lua deacat doua valori : 0 sau 1. De aici provine ideea de CLOCK POLARITY (CPOL):

  • DACA LA INITIEREA SS LOW SCK  ESTE 0 ATUNCI   CPOL   ESTE   0
  • DACA LA INITIEREA SS LOW SCK  ESTE 1 ATUNCI   CPOL   ESTE  1

      Acum mai ramane de explicat CPHA. Cand bitii incep sa se impinga intre ei in registrii si sa il dea afara pe ultimul din dreapta fac chestia asta ordonat in ritmurile SCK.  Dar cum o fac? Pentru a transmite 8 biti sunt necesare 8 perioade ale semnalului de ceas. Cum fiecare perioada are doua fronturi, unul crescator si altul descrescator si cum bitii se transmit numai pe aceste fronturi rezulta ca exista doar doua posibiliatati de transmitere: fie pe frontul crescator fie pe cel descrescator. Dar asta nu explica inca CPHA. Daca apelam la imaginea de mai sus si urmarim "X-urile" observam ca ele marcheaza primul front al primei perioade. Urmarind sagetile observam 2 lucruri: primul ar fi ca directia sagetii  indica daca frontul este crescator (LOW to HIGH) sau descrescator ( HIGH to LOW), iar cel de-al doilea ar fi faptul ca unele sageti sar peste primul front. Astfel se poate face urmatoarea afirmatie:

  • DACA BITII SE TRANSMIT PE PRIMUL FRONT PE CARE IL INTALNESC ATUNCI CPHA ESTE 0
  • DACA BITII SE TRANSMIT PE AL DOILEA  FRONT PE CARE IL INTALNESC ATUNCI CPHA ESTE 1.
      Combinand CPHA cu CPOL rezulta 4 moduri de functionare:

  1. Modul 1     CPOL =0  CPHA=0
  2. Modul 2     CPOL =0  CPHA=1
  3. Modul 3     CPOL =1  CPHA=0
  4. Modul 4     CPOL =1  CPHA=1
     Cele 4 moduri sunt universal valabile insa de fiecare data cand implementati acest protocol trebuie sa aveti in vedere doua lucruri: primul ar fi in care mod din cele 4 functioneaza perifericul iar cel de-al doilea cum se seteaza acest mod in interiorul uC.
      Acum la final, ca pentru amuzament voi prelua postarea userului " ckielstra " existenta pe forumul celor de la CCS C (compilator de C pentru microcontrollere din famila Microchip) la adresa  de aici :

// SPI Mode | MOTOROLA | MICROCHIP | CCS                          | Data clocked in at
//----------------------------------------------------------------|-------------------
//          | CPOL CPHA|  CKP CKE  |                              |
//    0     |  0    0  |   0   1   | SPI_L_TO_H | SPI_XMIT_L_TO_H | low to high edge
//    1     |  0    1  |   0   0   | SPI_L_TO_H                   | high to low edge
//    2     |  1    0  |   1   1   | SPI_H_TO_L                   | high to low edge
//    3     |  1    1  |   1   0   | SPI_H_TO_L | SPI_XMIT_L_TO_H | low to high edge 


     Simplu nu ????



Totalul afișărilor de pagină

Despre

Blog cu si despre electronica !