mars01 Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 (editat) Nu stiam despre acest gen de functie si acest gen de sintaxa. Dar nu este surprinzator. O functie o definesti si stii exact ce vrei sa faca. Daca vrei sa oferi o multitudine de valori, variabile ca parametri pentru functie, atunci folosesti un buffer, o arie care poate fi multidimensionala. Poti sa dai ca parametru unei functii un pointer catre o zona de memorie. Si pe urma tot ce ai de facut este sa incrementezi acel pointer pentru a accesa oricate variabile. Pentru tipuri diferite de variabile se pot da ca parametri pointeri corespunzatori. Etc. Genul de functie la care s-a facut referire merita mentionat doar ca o curiozitate dar nu mi se pare ca merita sa iti bati capul cu ea. Tot ce poti face cu acest tip de functii poti sa faci si cu tehnici de programare ortodoxe. Stiu ca am tot mentionat pointerii dar deocadata nu vreau sa incurc pe cei care sunt la inceput cu acest gen de informatii. Daca incep sa vorbesc despre pointeri, pointeri la pointeri etc o sa fie un oftat colectiv (pentru cei care urmaresc topicul). Pana la urma nu am amintit nimic nici despre arii si stringuri de caractere ... iar acestea vor trebui discutate chiar si numai pentru tiparirea unor texte pe un LCD. Editat Martie 2, 2016 de mars01 Link spre comentariu
Liviu M Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 Poti sa dai ca parametru unei functii un pointer catre o zona de memorie. Dupa cum scrie in linkul pe care l-am postat, printf e o astfel de functie. Banui ca daca era mai usor altfel, o implementau mai usor. Link spre comentariu
mars01 Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 (editat) In acest caz, e clar ca ma depaseste subiectul. Dar nici nu am pretentii ca programarea pentru PC imi este familiara. De-abia am inceput sa sap in aceasta directie. Editat Martie 2, 2016 de mars01 Link spre comentariu
Liviu M Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 (editat) Eu n-am folosit niciodata functii de-astea (in sensul ca n-am scris nici o astfel de functie), da' eu nu-s decat programator de duminica (sau de seara). Stiu de existenta lor pentru ca erau mentionate in cartea de C pe care am citit-o cu ani in urma. Editat Martie 2, 2016 de Liviu M Link spre comentariu
mars01 Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 (editat) Pentru ca a venit vorba despre carti de C, recomand cartea publicata de ed. Teora acum 4 ani, "Totul despre C si C++ - Manualul fundamental de programare in C si C++" scrisa de Dr. Kris Jamsa & Lars Klander. O gasiti aici. Si.... aici. Editat Martie 2, 2016 de mars01 Link spre comentariu
Liviu M Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 1328 pagini. :O Spor! Eu am K&R, ca pe asta mi-a recomandat-o cineva. Mi se pare o carte tare buna (informatie condensata, fara prea multe povesti), dar nu-s convins ca e cea mai buna pentru inceput (inainte de asta mai citisem cate ceva, nu eram chiar fresh). Link spre comentariu
mars01 Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 (editat) Mai putin de jumatate se ocupa de C. Sunt insa algoritmi buni acolo. LE: Aceasta este cartea? Aici. Editat Martie 2, 2016 de mars01 Link spre comentariu
Vizitator red_dog4ever Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 Am inceput sa ma plictisesc de arduino, asa ca vreau sa ma apuc de programarea pic-urilor. Cu ce procesor imi recomandati sa incep? Sunt multe pareri pro si contra pe google. As prefera sa nu coste foarte mult uP . Link spre comentariu
mars01 Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 (editat) Care vrei. Odata ce stii sa lucrezi cu unul ... Eu aici am sa incerc sa trec prin toate familiile PIC 8bit. Si daca se implica mai multa lume poate facem un topic pentru PIC32, dsPIC. Editat Martie 2, 2016 de mars01 Link spre comentariu
Liviu M Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 Am inceput sa ma plictisesc de arduino, asa ca vreau sa ma apuc de programarea pic-urilor. Cam ce crezi ca au in plus PIC-urile? Link spre comentariu
Vizitator red_dog4ever Postat Martie 2, 2016 Partajează Postat Martie 2, 2016 Invat ceva nou Link spre comentariu
mars01 Postat Martie 28, 2016 Partajează Postat Martie 28, 2016 (editat) Nu am mai scris aici in ultima vreme din lipsa de timp si partial ... lipsa de chef. Astazi vreau sa scriu putin despre manipularea porturilor la nivel binar. O sa vorbesc despre formatul binar, mascare (masking), shiftare biti la stanga sau la dreapta (left shifting, right shifting) si operatiile logice la nivel de biti. Extrem de plictisitor dar extrem de util cand se lucreaza cu registrii, porturile la nivel binar. 1. Formatul binar. Dupa cum stim, procesoarele (da, si microcontrolerele au inclus un procesor, asa numitul ALU: arithmetric logical unit) nu stiu de limbaje de nivel inalt. Ele nu stiu nici de limbaje de nivel jos, cum ar fi limbajul de asamblare. Ele stiu sa lucreze cu nivele de tensiune. Avem tensiune electrica sau nu avem tensiune electrica undeva anume. Cat anume este aceasta tensiune depinde de procesor / controler. La cele de care discutam noi (PIC pe 8 biti) printre tensiunile posibile sunt cele de 5V sau 3.3V adica Vdd, tensiunea de alimentare a controlerului (de fapt sunt controlere care incep sa functioneze de la tensiuni mult mai mici dar pentru simplificare am mentionat ce este mai sus). Cand tensiunea este prezenta undeva (mai exact este mai mare de cca 2V, vorbim de nivele TTL) se cheama ca avem 1 logic. Cand tensiunea lipseste (mai exact este mai mica de 0.6V) se cheama ca avem un 0 logic. Exista si nivelele CMOS si low-CMOS. Controlerele inteleg aceste nivele binare (1 si 0) in termeni de: adrese de memorie, date care se stocheaza la acele adrese de memorie si op code-uri (adica OPeration Code). Nici eu nu stiu prea multe cum functioneaza lucrurile aici dar la modul general procesorul "inhata" date de la o adresa din memoria RAM, le trece prin registri si apoi aplica acele op-code asupra acestor date. Aceste op-code pot fi sumari, substractari, multiplicari, divizari, shiftari, rotiri etc. Ma voi referi mai departe doar la controlerele pe 8 biti, cum am facut si pana acum. La acest tip de controlere, putem spune ca informatia este stocata in "unitati" de 8 biti. La PIC-uri arhitectura specifica poate organiza informatia/adrese pe 12/14 bit dar aceasta este o chestie de bucatarie interna. O asemenea unitate de 8 biti este numita byte (sau octet). Modul in care bitii sunt interpretati in biti este "little endian". Ce inseamna aceasta? Inseamna ca avem o conventie care spune ca bitul cel mai din stanga este bitul cu valoarea/eticheta cea mai mare iar bitul cel mai din dreapta este bitul cu valoarea/eticheta cea mai mica. Adica asa: bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 Am pus simbolul ' | ' pentru a servi ca separator vizual. Fiecare dintre cei 8 biti, de la bit7 pana la bit0, poate lua valoarea 0 sau 1. Pozitiei lui bit7 ii corespunde o valoare de 128 (adica 2 la puterea a 7-a), pozitiei lui bit6 ii corespunde valoarea de 64 (adica 2 la puterea a 6-a) si tot asa pana la pozitia lui bit0 careia ii corespunde valoarea 1 (adica 2 la puterea zero). Cu alte cuvinte avem o corespondenta asa: 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 Valoarea zecimala scrisa intr-un byte x de forma bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 este: x = 128 * bit7 + 64 * bit6 + 32 * bit5 + 16 * bit4 + 8 * bit3 + 4 * bit2 + 2 * bit1 + 1 * bit0 unde bit7 ... bit0 pot lua valori numai de 1 sau 0. Bun, la ce ne ajuta ce am scris mai sus? Ce valoare zecimala avem scrisa in byte-ul: 11101010 ? Pai 11101010 = 128 * 1 + 64 * 1 + 32 * 1 + 16 * 0 + 8 * 1 + 4 * 0 + 2 * 1 + 1 * 0 = 128 + 64 + 32 + 0 + 8 + 0 + 2 + 0 = 234 2. Despre shiftare (deplasa biti la stanga sau la dreapta). Avem forma urmatoare: 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 bit7 | bit6 | bit5 | bit4 | bit3 | bit2 | bit1 | bit0 Dupa cum putem vedea fiecare pozitie este inconjurata de pozitii cu valoare dubla sau la jumatate. Evident exceptie bitul7 si bitul 0 care se invecineaza doar cu cate o pozitie (bit6, respectiv bit1). Cu alte cuvinte, daca am deplasa pozitia la un 1 de la dreapta la stanga, practic valoarea finala in byte se dubleaza ( *2). Iar daca am deplasa pozitia unui 1 de stanga la dreapta, valoarea finala a unui byte se injumatateste (/2). Aceasta este shiftarea. Ex: 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 Val initiala 0 1 0 0 0 1 0 0 In zecinal ce este scris mai sus are valoare: 128*0 + 64*1 + 32*0 + 16*0 + 8*0 + 4*1+ 2*0 + 1*0 = 68 Daca shiftam val initiala cu o pozitie la dreapta ne asteptam ca valoarea finala sa se injumatatesca: 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 Val initiala 0 0 1 0 0 0 1 0 In zecinal ce este scris mai sus are valoare: 128*0 + 64*0 + 32*1 + 16*0 + 8*0 + 4*0+ 2*1 + 1*0 = 34 Si chiar asa si este. Daca shiftam val initiala cu 3 pozitii la stanga ne asteptam ca valoarea finala sa se dubleze de 3 ori (2 * 2 * 2): 128 | 64 | 32 | 16 | 8 | 4 | 2 | 1 Val initiala 0 0 1 0 0 0 0 0 In zecinal ce este scris mai sus are valoare: 128*0 + 64*0 + 32*1 + 16*0 + 8*0 + 4*0+ 2*0 + 1*0 = 32 Si chiar asa si este. 1-ul din pozitia bit 6 se deplaseaza la stanga pana dispare, iar 1-ul de pe pozitia bit2 ajunge (asa s-a nimerit) in pozitia lui bit6. Doar ca ... valoarea rezultata nu este chiar cat ar trebui sa fie. De ce? 68 * 2 * 2 * 2 = 544 Dar pe 8 biti putem scrie maxim 255! Deci valoarea rezultata este (datorita fenomenului de roll-over): 544 - 256 = 288 Inca un rollover (valoarea este mai mare ca 255) deci: 288 -256 = 32. Exact valoarea pe care o vedem: Intrebarea este ... am shiftat noi la stanga de 3 ori dar ce a intrat in pozitia bit0, bit1 si bit2? Ca este clar ca acolo intra ceva necunoscut pentru ca nu este "nimic" dincolo de pozitia bit0 (spre dreapta ma refer). In principiu se considera ca la shiftare intra 0-uri pe pozitiile descoperite de la margine (ori ca este marginea din stanga a byte-ului ori marginea din dreapta). Dar am vazut ca multi programatori se asigura ca acele pozitii sunt zero folosind mascarea (bit masking) pe care o sa o descriu mai jos. In limbajul C, shiftarea se realizeaza cu urmatorii operatori: ' << ' se foloseste pentru shiftarea la stanga ' >> ' se foloseste pentru shiftare la dreapta EXEMPLU: Un exemplu de programel care shifteaza la stanga un bit 1 pe portul C, si cand ajunge la bit 7 o ia de la capat. Daca punem LED-uri pe portul C (deci vor fi 8 LED-uri) practic vom vedea un LED aprins care se plimba de la dreapta la stanga si tot asa. Controler folosit: PIC seria 18F: PIC18F14K22 Se foloseste oscilatorul intern, cu PLL setat ON (adica se multiplica cu 4 frecventa). Frecventa de lucru este astfel 64MHz. Cum la PIC instructiunea dureaza 4 cicli de clock rezulta ca avem cel mult 16 MIPS (16 milioane instructiuni pe secunda). Pinul de reset MCLR este dezactivat (deci este tinut intern in 1 logic si deci nu trebuie sa ne mai ocupam noi in circuit). Setarile sunt asa: Datahseet-ul este aici: http://ww1.microchip.com/downloads/en/DeviceDoc/41365D.pdf iar aici avem registrii de configurat ca sa ne putem face treaba cu portul C, nestingheriti (est evorba de pagina 93 din datasheet): Programul este acesta: //functie de configurare a perifericelorvoid init_sys() { // dezactivare convertoare ADC ANSEL = 0; ANSELH = 0; SLRC_bit = 0; // configurez slew-rate-ul pentru iesiri la viteza maxima DAC1OE_bit = 0; // dezactivare DAC // dezactivare comparatoare C1ON_bit = 0; C2ON_bit = 0; TRISC = 0b00000000; // portul C este format tot din iesiri LATC = 0b00000000; // se porneste cu toti pinii port C in stare LOW }void main() { int i; // variabila contor din ciclul for de mai jos init_sys(); // apel functia de configurare a registrilor perifericelor LATC = 0b00000001; // aprindem primul LED care apoi va fi 'plimbat' // bucla infinita while (1) { for (i = 0; i < 7; i = i +1) { LATC = LATC << 1; // shiftare a valorii initiale a LATC Delay_ms(100); // un delay cat sa stea LED-ul in starea curenta. } LATC = 0b00000001; // aprindem primul LED pentru urmatorul ciclu care apoi va fi 'plimbat' Delay_ms(100); // un delay special pentru starea precedenta a LATC }} Efectul este asa: Dupa cum vedeti acest controler are un numar de registri noi. Nu am de gand sa ii tratez pe toti dar vreau sa mentionez doar unul dintre ei. Mai exact este vorba de registrul LATx, unde x este litera portului (A,B,C etc functie de tipul de controler seria 18F folosit). Acest registru LATx este un registru care este caracteristic seriei de controlere 18F si a unei parti din seria 16F. El controleaza pinii setati ca iesire si le seteaza in 1 sau 0 dupa caz. La seria 16F, controlul pinilor setati ca iesire dar si cei setati ca intrari era efectuat cu un singur registru PORTx (unde x este litera portului). La seria 18F (cat si la seria advanced 16F), se poate proceda la fel ca la seria standard 16F, folosindu-ne numai de registrul PORTx. Sau se poate folosi PORTx numai pentru citirea stare intrari si LATx pentru controlul starii iesirilor, asa cum este recomandat. Registrul LATx a aparut ca solutie a unei probleme numite READ - MODIFY - WRITE. Nu intru in detalii, daca vreti cititi despre aceasta, problema este bine documentata pe forumurile Microchip, vreau doar sa va recomand sa folositi registrul LATx de cate ori aveti de ales pentru ca este mult mai eficient si va scapa de dureri de cap de care nici nu stiti ca exista. Va urma. LE: in GIF-ul de mai sus am pus pinul MCLR in VCC (din motive pe care numai proteus le stie, desi am setat MCLR disabled in configurare, nu tine cont si a fost necesar acest HIGH pe pinul MCLR facut in circuit ca sa nu stea in reset permanent). Editat Martie 28, 2016 de mars01 Link spre comentariu
Vezi Muti Postat Martie 28, 2016 Partajează Postat Martie 28, 2016 mars01, daca tot ziceai ca nu ai avut chef, dau un motiv sa explici si operatorul "|". codul contine mai putine linii asa: void main() { int i; init_sys(); LATC = 0b00000001; while (1) { LATC = (LATC << 1) | (LATC >> 7); // 'rotire' a valorii initiale a LATC Delay_ms(100); }} felicitari pentru rabdare si stil de expunere. Link spre comentariu
mars01 Postat Martie 29, 2016 Partajează Postat Martie 29, 2016 (editat) 3. Despre operatiile la nivel de biti Operatiile uzuale la nivel de biti sunt (doar o enumerare): AND - functioneaza pe tabela de adevar gasita la portile AND (si); operator C: ' & ' OR - functioneaza pe tabela de adevar gasita la portile OR (sau); operator C: ' | ' XOR - functioneaza pe tabela de adevar gasita la portile XOR (sau exclusiv); operator C: ' ^ ' NOT - functioneaza pe tabela de adevar gasita la portile Inverter (complement fata de 1, inversor); operator C: ' ~ ' (si cele deja explicate: right shift, left shift). Ce inseamna operatii la nivel de biti? Daca avem doi bytes de forma: byte1 = bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 byte2 = bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 cand aplicam o operatie binara (adica AND sau OR sau XOR sau NOT) intre bytes1 si bytes2, acea operatie se face intre bitii corespondenti aflati pe acea pozitie. Cu alte cuvinte, o operatie binara aplicata pe cei doi bytes se face aplicand operatia: intre bit7 al byte1 si bit7 al byte2, intre bit6 al byte1 si bit6 al byte2 si tot asa pana la: intre bit0 al byte1 si bit0 al byte2. Nu intru in detalii, daca vreti sa vedeti tabelele de adevar le puteti verifica de ex aici. IMPORTANT: Ce trebuie sa stiti este ca: AND intre doi biti este ca si cum ii inmultiti OR intre doi biti este ca si cum ii adunati (doar ca 1 + 1 este tot 1) XOR intre doi biti este ca si cum ii adunati (doar ca 1 + 1 este 0) NOTA: mai sus ma refer la biti (aflati pe aceasi pozitie) si nu la bytes. OK? Operatia NOT se aplica unui singur byte si nu intre doi bytes. Practic operatia NOT schimba starea, bit cu bit, pentru tot byte-ul (din 0 in 1 si din 1 in 0) Exemple: byte1 = 0 0 1 0 0 0 1 1 byte2 = 0 1 1 1 0 0 1 0 byte1 & byte2 = 0 0 1 0 0 0 1 0 (puteti vedea ca se inmultesc efectiv fiecare doi biti) byte1 | byte2 = 0 1 1 1 0 0 1 1 (se poate vedea ca se aduna efectiv bitul de sus cu bitul de jos si daca ambii biti sunt 1 se pune tot 1) byte1 ^ byte2 = 0 1 0 1 0 0 0 1 (se poate vedea ca se aduna efectiv bitul de sus cu bitul de jos si daca ambii biti sunt 1 se pune de data aceasta 0) ~byte 1 = 1 1 0 1 1 1 0 0 (se vede ca fiecare bit din byte1 este inversat) ~byte 2 = 1 0 0 0 1 1 0 1 (se vede ca fiecare bit din byte2 este inversat) Operatia XOR este folosita pentru a face toggle (adica schimbare de stare pentru anumiti biti). Tot ce trebuie facut este ca pe un anume byte, sa ii faceti XOR cu o valoare care are 1 pe bitul unde vrem sa facem toggle acelui bit al byte. Spre exemplu avem registrul PORTC (care dupa cum spuneam grupeaza un numar de 8 biti care controleaza fiecare starea unui pin care in prealabil a fost setat ca iesire in registrul TRISC; sau daca vorbim de controlere seria 18F sau 16F adavanced, acelasi efect se obtine din registrul LATC dar protejat la problema read-modify-write). Bun, vorbim de registrul PORTC. Vrem sa schimbam starea (facem toggle, adica inversam starea unui bit) DOAR si numai DOAR pentru bitul 3. Facem asa: PORTC = PORTC ^ 0b00001000; In acest fel nu ne intereseaza ce valoare are bitul 3 din PORTC. De fiecare data cand se executa linia de mai sus, starea bitului 3 din PORTC se schimba in opus (daca era 0 devine 1, daca era 1 devine 0) Cred ca puteti vedea ca se poate face foarte usor un "licurici" asa, nu? void main() { // configuram aici registrii pentru dezactivare ADC, comparatoare etc / eu nu fac aceasta // din motive de ... lene; daca vreti un program functional va trebui sa o faceti dvs. // Cu datasheet-ul in fata. TRISC = 0b00000000; // portul C este tot format din iesiri PORTC = 0b00000000; // portul C este initializat cu 0; fiecare pin asociat unui bit este LOW delay_ms(500); // un delay de 500ms ca sa putem vedea si starea initiala, nu? // bucla infinita while (1) { PORTC = PORTC ^ 0b00001000; // se schimba starea pinului corespondent bit3, pe restul ii lasam in pace ... // daca vroiam sa schimb starea la 3 biti, adica licurici pe trei biti (sa zicem bit7, bit3 si bit0) faceam linia de mai sus asa: // PORTC = PORTC ^ 0b10001001; delay_ms(500); // un delay de 500ms ca sa putem vedea efectiv starile cum se schimba la fiecare 500ms }} Cam asta este efectul (doar ca folosind un PIC18F am inlocuit registrul PORTC cu LATC in program) Sau pentru un PIC18F14K22, un mic joc de lumini facut aiurea cu doar cateva modificari. Doar ca sa vedeti utilitatea imediata a "jonglarii cu biti". Setarile CONFIG sunt cele postate anterior pentru PIC18F14K22. //functie de configurare a perifericelorvoid init_sys() { // dezactivare convertoare ADC ANSEL = 0; ANSELH = 0; SLRC_bit = 0; // configurez slew-rate-ul pentru iesiri la viteza maxima DAC1OE_bit = 0; // dezactivare DAC // dezactivare comparatoare C1ON_bit = 0; C2ON_bit = 0; TRISC = 0b00000000; // portul C este format tot din iesiri LATC = 0b00000000; // se porneste cu toti pinii port C in stare LOW }void main() { init_sys(); TRISC = 0b00000000; // portul C este tot format din iesiri LATC = 0b00000000; // portul C este initializat cu 0; fiecare pin asociat unui bit este LOW delay_ms(500); // un delay de 500ms ca sa putem vedea si starea initiala, nu? // bucla infinita while (1) { LATC = LATC ^ 0b10101010; delay_ms(500); // un delay de 500ms ca sa putem vedea efectiv starile cum se schimba la fiecare 500ms LATC = LATC ^ 0b01010101; delay_ms(500); // un delay de 500ms ca sa putem vedea efectiv starile cum se schimba la fiecare 500ms }} Editat Martie 29, 2016 de mars01 Link spre comentariu
Postări Recomandate
Creează un cont sau autentifică-te pentru a adăuga comentariu
Trebuie să fi un membru pentru a putea lăsa un comentariu.
Creează un cont
Înregistrează-te pentru un nou cont în comunitatea nostră. Este simplu!
Înregistrează un nou contAutentificare
Ai deja un cont? Autentifică-te aici.
Autentifică-te acum