Sari la conținut
ELFORUM - Forumul electronistilor

Invatat programare de la zero


riciu

Postări Recomandate

Cam despre asta era vorba : daca am un delay_ms , in general avem o intarziere in care controlerul "numara" , netrecand la linia urmatoare pana cand nu termina de numarat ; daca delay_ms urmeza dupa o incrementare/decrementare el aloca acestei operatii un anumit interval de timp . Asadar :intarzierea nu va fi cea data de "delay_ms(valoare) ci de valoarea pana la care se incrementeaza/decrementeaza impartita la valoarea din "delay_ms" ...

 

Cred ca Einstein a spus ca n-ai inteles cu adevarat un fenomen pana cand nu esti in stare sa-l explici bunicii ; nu am indoieli ca ati inteles lucrurile pe care le discutam , cer doar sa fiu ... pe post de bunica  :rade: .

Link spre comentariu

...dupa care urmeaza functia delay_ms(valoare) care aloca un anumit interval de timp in care sa se efectueze incrementarea/decrementarea respectiva ; in cazul nostru 10 ms . Stiu ca in cele 10 ms controlerul nu sta efectiv ci numara ... 

 

 

De fapt chiar aceasta se intampla in timpul instructiunii delay_ms(x) unde x - nr de milisecunde. Controlerul NU numara, nu face nimic in aceasta perioada specificata in functia delay_ms(x). Controlerul sta degeaba. Cel putin dpdv al programului principal, pentru ca de fapt el numara NOP-uri. Functia delay_ms(x) este o functie blocatoare (macro in unele cazuri dar o sa discutam ce este un macro cand vom lamuri chestia cu #define).

 

Controlerul PIC, de fapt procesorul aritmetric din acesta, are o instructiune speciala numita NOP. Aceasta denumire vine de la No OPeration (asa imi aduc aminte ca este interpretarea acronimului). Efectiv bate pasul pe loc fara sa faca nimic pentru un anumit numar de cicli (cate instructiuni NOP sunt, tot atatia cicli de executie se sta degeaba). Fiecare instructiune NOP consuma un ciclu de executie al procesorului.

 

Liviu a explicat mai sus foarte clar ce este cu functia delay_ms(x).

 

Functia delay_ms(x) este un bloc de cod in care se executa mai multe sau mai putine instructiuni asamblare NOP. Cat de multe sunt acestea, depinde de cat timp vrem ca sa fie controlerul in asteptare (sa bata pasul pe loc).

De unde stie controlerul cate instructiuni NOP sa asigneze pentru un timp dat, este o treaba de bucatarie interna a compilatorului (evident trebuie sa stie la ce frecventa lucreaza controlerul ca sa poata decide de cate instructiuni_care_nu_fac_nimic NOP este nevoie). Evaluarea aceasta, cate instructiuni NOP sunt necesare, este efectuata in momentul compilarii programului. Adica atunci cand apasati pe butonul BUILD in interfata grafica a compilatorului.

 

LE: Ne luand in seama intreruperile, practic atata timp cat procesorul sta si deserveste functia delay_ms, el nu face nimic altceva decat sa numere NOP-uri. Dpdv al programului, totul s-a oprit pana se termina functia delay_ms(x).

Este ca si cand o masina se opreste in intersectie. Toti ceilalti stau dupa ea pana cand se urneste din loc.

 

Cred ca inteleg de unde vine confuzia ta. Rolul functiei delay_ms(x) este ca sa se asigure ca cu fiecare decrementare al variabilei timp, timpul ramas din temporizare scade cu 10ms. Daca nu ar fi functia delay_ms(x) atunci intr-adevar temporizarea s-ar termina dupa aproximativ 60000 de cicli de executie + ciclii de executie consumati de programul din bucla while (timp != 0), plus ce se mai executa pe acolo deci intr-un final cca 500000 ... 1 milion de cicli de executie (cifre date din burta dar n-am chef de numarat instructiuni asamblare, sorry) care ar echivala cu 100ms ... 200ms.

 

@iuli09, daca nu ai inteles inca, sau ti se pare doar ca intelegi ceva ceva dar tabloul nu este complet, spune. Am sa incerc sa explic altfel sau un coleg va veni cu o explicatie mai buna.

Nu tu ai ceva ca nu intelegi ci doar eu/noi nu ne adaptam incat sa putem comunica cu tine. Toti avem un bagaj diferit de experiente si este normal ca ceea ce este foarte clar pentru unul sa nu fie pentru altul.

Insista cu intrebarile pana te lamuresti si nu te da batut. Toti am fost incepatori, eu inca ma consider unul.

Editat de mars01
Link spre comentariu

Bun ! incet-incep ies si eu din ceata ...

 

Acum : am o placa de dezvoltare construita in jurul unui PIC 16F887 , mai exact asa ceva :

 

Posted Image

 

 

M-am gandit ca ar fi un exercitiu bun sa modific programul tau pentru a functiona pe dispozitivul meu . 

 

Problema e ca atunci cand am incercat sa-l compilez nu s-a putut .Erorile raportate au fost :

 

-"13 324 Undeclared identifier 'CMCON' in expression..."

-"15 324 Undeclared identifier 'CVRCON' in expression ..."

 

 

 

 

Mi-am bagat putin nasul pe aici :  

 

 

http://ww1.microchip.com/downloads/en/DeviceDoc/41291G.pdf

 

 

http://www.mikroe.com/chapters/view/16/chapter-3-pic16f887-microcontroller/#c3v3

 

http://www.mikroe.com/chapters/view/8/chapter-7-analog-modules/

 

...si am facut modificarile care mi s-au parut necesare si acum programul functioneaza .

 

Programul modificat arata asa :

 void main() {    /*declaram o variabila numita timp, de tip unsigned int - deci poate lua valori intre 0 si 65535  Aceasta variabila va tine in ea numarul de zeci de milisecunde care va constitui perioada de temporizare.  Initializam aceasta variabila cu val 100 care corespunde la 100 cicluri de 10ms adica 1 secunda */  unsigned int timp = 100;  /*Declaram doua constante ON si OFF ca sa ne fie mai usor de inteles programul*/  const unsigned char ON = 1;  const unsigned char OFF = 0;  /************** INITIALIZARE***************************/  ANSEL = ANSELH = 0; // All I/O pins are configured as digital  C1ON_bit = C2ON_bit = 0; //dezactivam comparatoare  ADCON0 = 0;          //dezactivam ADC  VREN_bit = 0;          //dezactivam referinta variabila de tensiune  TRISB = 0b00000001;  //facem INTRARE din pinul2 adica RB0; aici vom avea switch-ul conectat  TRISD = 0b00000000;  //facem IESIRE din pinul 33 adica RD0; aici vom avea LED-ul conectat  PORTD = 0b00000000;  //pornim cu LED-ul atasat pe pinul33 stins. Adica RD0 = LOW;  /**************SFARSIT INITIALIZARE********************/  /*urmeaza bucla infinita Cat timp 1 este egal cu 1(si 1 este egal cu 1 tot timpul) executa ce este intre acolade  */  while(1 == 1) {    if (RB0_bit == 0) {   //daca intrarea este LOW      delay_ms(10);       //asteptam 10 milisecunde      if (RB0_bit == 0) { //daca intrarea inca mai este LOW atunci chiar ca avem o apasare reala de switch        RD0_bit = RD2_bit = RD4_bit = RD6_bit = ON;    //aprindem LED-ul        while (timp != 0) {     //cat timp timpul este diferit de zero          /*Urmatoarele doua conditii if(expresie) se folosesc pentru ca daca cumva in timpul de asteptare mai apasam          cumva pe buton, timpul trecut se reseteaza si temporizarea o ia de la inceput*/          if (RB0_bit == 0) {   //daca intrarea  este LOW            delay_ms(10);       //asteptam 10 milisecunde            if (RB0_bit == 0) { //daca intrarea inca mai este LOW atunci chiar ca avem o apasare reala de switch              timp =  100;     //resetam timpul la valoarea initiala, 100 * 10ms = 1000ms = 1sec            }          }          //variabila timp va scadea cu o unitate pentru fiecare ms care trece          timp = timp - 1;      // sau se poate scrie timp--;          delay_ms(1);         //aceasta este intarzierea esentiala pentru cronometrarea timpului cat LED-ul sta aprins        }        //timpul cat LED-ul trebuie sa stea ON a trecut si acum facem LED-ul OFF        RD0_bit = RD2_bit = RD4_bit = RD6_bit = OFF;        timp = 100;      }    }  }} 

Am vazut ca functioneaza si fara acste linii :

 

"C1ON_bit = C2ON_bit = 0; //dezactivam comparatoare
ADCON0 = 0; //dezactivam ADC
VREN_bit = 0; //dezactivam referinta variabila de tensiune"

 

Practic , modificarea pe care trebuia neaparat s-o fac era aceasta :  "ANSEL = ANSELH = 0; // All I/O pins are configured as digital" .

 

 

Intrebarea ar fi : de ce nu a fost necesara aceasta linie in programul original (cel pentru 16F877) ?

Editat de iuli09
Link spre comentariu

Ca sa fii sigur ca n-o sa ai surprize, iei foile de catalog ale ambelor dispozitive si, in cazul erorilor, vezi ce trebuie sa modifici pentru a obtine aceeasi functionalitate.

Editat de Liviu M
Link spre comentariu

Functiile in C

 

O functie este de fapt un bloc de linii de program care sunt executate impreuna, avand scopul de a executa o sarcina.

 

Ne amintim de functiile de la matematica, cea mai simpla fiind ecuatia lineara:

 

f(x) = a*x + b

unde a si b sunt doua variabile a caror valoare este stiuta (am putea in acest fel sa le facem de tip constant daca vrem, dar le putem lasa si ca variabile normale) iar x este necunoscuta. toti 3 sunt parametri pentru functie

 

O functie are un numar de parametri si un rezultat. Intotdeuna avem un singur rezultat dintr-o functie desi aceasta limitare se poate ocoli folosind variabile de tip pointer si/sau variabile de tip structura.

 

Acesti parametri, cat si rezultatul, sunt variabile la care trebuie declarate tipurile.

 

In acest fel o functie trebuie mai intai declarata iar apoi definita. Si intr-un final ea va fi utilizata (called) undeva in programul principal. Intotdeauna declaratia se face la inceputul programului.

 

Un exemplu de functie este cea de mai sus, ecuatia lineara.

 

Aceasta se declara (la inceputul programului), un exemplu ar fi asa:

// tip_rezultat linear_func(tip_parametru1, tip_parametru2, tip_parametru3);int linear_func (int, int, int);

Ce inseamna aceasta?

Inseamna ca functia va intoarce (cu ajutorul instructiunii RETURN) un rezultat cu tipul int (este vorba de primul int de mai sus) si va accepta trei parametri, toti de tip int, evidentiati intre parantezele rotunde.

Ne putem da seama astfel ca functia va avea trei parametri si fiecare poate lua valori intre -32768 si 32767 ( sunt tipul int si fiindca nu avem modificatorul specficat in fata, in mod default este asumat modificatorul signed).

Ne dam seama si ca functia  va avea valori intre -32768 si 32767 (pentru ca are un rezultat tot de tipul int).

 

O functie poate sa nu aiba un rezultat si/sau o functie poate sa nu aiba parametri. In acest caz se spune ca functia intoarce un rezultat de tip void si respectiv, admite parametru de tip void

 

In ce caz o functie nu intoarce nici-un rezultat? Pai avem cel putin urmatoarele situatii:

- cand functia are un rezultat sau chiar mai multe dar sunt folosite subterfugii care ocolesc calea normala (pointeri, structuri) de a intoarce rezutlate.

- cand functia are un efect asupra unui modul (periferic) din controller. De ex o functie care tipareste pe un LCD nu are nevoie sa mai intoarca un rezultat intr-o variabila pentru ca rezultatul este insasi afisarea pe LCD a ceea ce dorim sa afisam.

- cand functia isi scrie rezultatul intr-o variabila (sau mai multe) globala. Nu am discutat inca despre variabile globale, locate, volatile, static. Dar o sa o facem.

 

In ce caz nu avem nevoie de parametri la o functie?

Pai de ex, daca avem o functie care citeste starea unui button atasat unui pin al controlerului si intoarce starea acestui pin, evident ca aceasta functie isi ia datele din mediul exterior printr-un registru (variabila tip registru). Registrii, daca sunt priviti ca variabile, nu au nevoie sa fie declarati cu un tip.

De ce?

Pentru ca stim ca registrii sunt intotdeuna pe 8 biti (pentru cazul microcontrolerelor pe 8 biti despre care discutam, registiri sunt intotdeuna pe 8 biti si se gasesc mereu la aceasi adresa in memorie). Asa ca nu are nici-un rost sa declaram registrii si producatorii de compilatoare au tinut cont de aceasta. Probabil ca mai sunt si alte considerente dar eu nu am habar de altele si mi-este suficient sa stiu ca registrii nu trebuie declarati.

 

Oriunde altundeva, dar nu in functia principala (acea functie pe care orice program C trebuie sa o aiba si care are sintaxa void main() ) se defineste functia.

 

Definirea unei functii inseamna sa ii scrii corpul, adica ce face exact.

 

In exemplul de mai sus cu ecuatia lineara, definirea functiei arata asa:

int linear_func (int a, int b, int x) { int res; res = a*x + b; return res;}

In cadrul programului principal (care se gaseste intotdeuna in functia void main() ) de exemplu vom apela (chema, "call") functia linear_func asa (urmeaza un program complet):

int linear_func(int, int, int); //declararea functiei sau asa numitul prototip//aici definim functiaint linear_func (int a, int b, int x) {  int res;  //declaram o variabila locala care va stoca rezultatul  res = a*x + b; //aici efectuam operatia asupra parametrilor si obtinem un rezultat res  return res; //aici intoarcem rezultatul}void main() {  //functia principala  int rezultat_functie; //declaram o variabila de tip int in care vom stoca rezultatul care vine din functie  int parametru_a = 10; //declaram o variabila de tip int pentru parametrul a si o initializam (e doar un ex)  int parametru b = 5;  //declaram o variabila de tip int pentru parametrul ba si o initializam (e doar un ex)  unsigned char i;      //declaram o variabila de tip unsigned char pentru ciclul for    for (i = 0; i < 10; i=i+1) {  // o bucla care se va executa de 10 ori    rezultat_functie = linear_func(parametru_a, parametru_b, i);  // se apeleaza functia pentru fiecare valoare a lui i    printf("Rezultatul este: %d n", res); //pentru fiecare valoarea a lui i se tipareste pe "ecran" rezultatul  }}

Functia printf(parametri) nu este o functie uzuala in lumea embedded dar ca si exemplu merge si asa. De fapt, in IDE-ul MPLAB (pluginul Code Configurator) se poate face o asociere intre driverul UART si aceasta functie.

Ca si efect rezultatul acestei functii este afisarea pe ecran a ceva.

As fi putut sa fac un program care sa foloseasca functiile de tiparire pe un LCD dar complicam inutil programul si acum nu prea am timp sa intru in detalii.

 

Observati cum se apeleaza functia linear_func in interiorul functiei void main().

 

Nota:

Cand folosim functiile?

 

Atunci cand:

 - avem o bucata de cod pe care o reutilizam de multe ori intr-un program. In loc sa facem o lista kilometrica de instructiuni scriind de fiecare data acea bucata de cod, mai bine o transformam intr-o functie si o reutilizam de fiecare data cand este necesar printr-un simplu apel.

 - dorim sa modularizam un program. Daca stim ca pe viitor vom schimba acea functie (din diverse motive), este mai usor sa ii modificam corpul acelei functii intr-un singur loc in program decat sa stam as vanam "functionalitatea" prin program si sa inlocuim bucati de cod pe ici pe colo. Cand avem un program mic , e OK si asa,  sa stai sa modifici peste tot, dar cand programul are zeci de mii de linii de cod, este o munca titanica sa schimbi peste tot unde este cazul.

 - altele care nu imi vin in minte acum. Simtiti-va liberi sa adaugati.

 

Va urma.

 

LE: data viitoare o sa rescriem programul "licurici" folosit prin primele posturi de pe topic si o sa ne folosim de functii.

Editat de mars01
Link spre comentariu
Chiar si cu argumente de tip char rezultatul functiei "linear" n-ar incapea intr-un int.
Daca se asteapta un rezultat corect de la o functie,  trebuie atentie mare la declararea tipului de date pentru argumentele functiei, dar si pentru datele returnate de catre functie.
In functia linear res=a*x + b, daca avem a=256, b=256 si x=256 res=65792, adica cu 257 peste 65535.
Mars01 a vorbit despre rollover undeva pe la inceput si probabil ca aici a vrut sa testeze atentia celor care sunt dornici sa invete.
Link spre comentariu

Nope, treaba cu tipurile variabilelor este o scapare a mea.

 

Intra-devar iti evaluezi tipurile la variabile functie de ce intentionezi sa faci.

In apararea mea, am lasat tipurile int, acesta fiind un fel de default pentru multe compilatoare, si m-am axat mai mult sa explic ce e cu functiile. De altfel si functia are valori la parametri care nu creaza nici-o problema de rollover. Asa ca in cazul acesta particular nu se pune problema de rollover.

Daca insa vrei sa refolosesti functia atunci trebuie mare atentie; eventual schimbat tipul rezultatului din int in long.

 

Oricum nici treaba aceasta cu explicatul functiilor nu am facut-o multumitor. Insa nu am terminat subiectul asa ca poate am sa fiu mai inspirat data viitoare.

 

Dar multumesc @elison este o observatie foarte buna si care arata ca in programare trebuie sa fii foarte atent altfel apar tot felul de bug-uri de numai stii de unde sa apuci problema de gat.

 

Adevarul este ca imi place cand se implica mai multe persoane, sper ca sa fie util ce scriu si sa nu scriu degeaba. Si asa sunt destul de obosit in perioada aceasta, azi  de-abia am gasit  putin timp ca sa scriu despre functii.

Editat de mars01
Link spre comentariu

Am fost intrebat de ce programul din postul #128, mai exact exemplul nostru, nu functioneaza cum trebuie.

Sincer nu l-am testat asa ca am facut rapid o simulare in Proteus si am observat ca bitul 0 al portului A, adica bitul RA0 pe care este conectat switchul nostru (bitul RA0 corespunde pinul 2 al controlerului) este mereu in starea LOW indiferent ca este tras spre Vcc printr-un rezistor de pull-up.

 

In acest moment mi-a fost clar ca e o problema de configurare a registrilor aferenti acelui pin.

Pinul RA5 face parte din portul A. Registrii PORTA si TRISA sunt configurati corect deci ramane ceva legat de functiile analogice. Tot pe pinul 2 se gaseste si intrarea analogica AN0.

Este clar la acest punct ca desi am dezactivat convertorul ADC prin atribuirea valorii 0 registrului ADCON0, aceasta nu este suficient.

In continuare m-am uitat in datasheet si la pagina 128 (ce coincidenta postul #128 isi gaseste rezolvarea in pagina 128 din datasheet :) ) avem registrul ADCON1.

Observam ca intrarea AN0 este dezactivata (pinul ramane digital, D) numai atunci cand bitii PCFG3:PCFG0 sunt 011x (x inseamna ca poate fi orice).

Astfel se pare ca trebuie sa scriem in registrul:

ADCON1 = 0b00000110;

(nu conteaza ce avem pe bitii 7:4 si nici pe bitul 0 asa ca am pus valoarea 0 acolo; nu conteaza pentru ca oricum nu folosim modulul ADC)

 

sau folosindu-ne de sintaxa mikroC putem scrie:

PCFG3_bit = 0;PCFG2_bit = 1;PCFG1_bit = 1;PCFG0_bit = 0;

Posted Image

 

Prin urmare programul corect ar arata asa:

void main() {  /*declaram o variabila numita timp, de tip unsigned int - deci poate lua valori intre 0 si 65535  Aceasta variabila va tine in ea numarul de zeci de milisecunde care va constitui perioada de temporizare.  Initializam aceasta variabila cu val 60000 care corespunde la 60000 cicluri de 10ms adica 10minute */  unsigned int timp = 60000;    /*Declaram doua constante ON si OFF ca sa ne fie mai usor de inteles programul*/  const unsigned char ON = 1;  const unsigned char OFF = 0;      /************** INITIALIZARE***************************/  CMCON = 0b00000111;  //dezactivam comparator  ADCON0 = 0;          //dezactivam ADC  ADCON1 = 0x6;        //totuna cu ADCON1 = 0x00000110; facem toate intrarile analogice, digitale.  CVRCON = 0;          //dezactivam referinta variabila de tensiune   TRISA = 0b00000001;  //facem INTRARE din pinul2 adica RA0; aici vom avea switch-ul conectat   TRISB = 0b00000000;  //facem IESIRE din pinul 33 adica RB0; aici vom avea LED-ul conectat  PORTB = 0b00000000;  //pornim cu LED-ul atasat pe pinul33 stins. Adica RB0 = LOW;  /**************SFARSIT INITIALIZARE********************/   /*urmeaza bucla infinita Cat timp 1 este egal cu 1(si 1 este egal cu 1 tot timpul) executa ce este intre acolade  */  while(1 == 1) {        if (RA0_bit == 0) {   //daca intrarea este LOW      delay_ms(10);       //asteptam 10 milisecunde      if (RA0_bit == 0) { //daca intrarea inca mai este LOW atunci chiar ca avem o apasare reala de switch        RB0_bit = ON;    //aprindem LED-ul                while (timp != 0) {     //cat timp timpul este diferit de zero          /*Urmatoarele doua conditii if(expresie) se folosesc pentru ca daca cumva in timpul de asteptare mai apasam          cumva pe buton, timpul trecut se reseteaza si temporizarea o ia de la inceput*/          if (RA0_bit == 0) {   //daca intrarea  este LOW            delay_ms(10);       //asteptam 10 milisecunde            if (RA0_bit == 0) { //daca intrarea inca mai este LOW atunci chiar ca avem o apasare reala de switch              timp =  60000;     //resetam timpul la valoarea initiala, 60000 * 10ms = 600000ms = 600sec = 10minute            }          }          //variabila timp va scadea cu o unitate pentru fiecare 100ms care trec          timp = timp - 1;      // sau se poate scrie timp--;          delay_ms(10);         //aceasta este intarzierea esentiala pentru cronometrarea timpului cat LED-ul sta aprins                  }        //timpul cat LED-ul trebuie sa stea ON a trecut si acum facem LED-ul OFF        RB0_bit = OFF;        timp = 60000;      }    }   }}

LE: Atasez si simularea (timpul din temporizare este micsorat la 3secunde pentru a nu ne plictisi asteptand) in Proteus 8.4

 

example.zip

Editat de mars01
Link spre comentariu
Vizitator ciocanaru

Tin sa multumesc si eu lui Mars01 in special precum si si celorlalti participanti la topic pentru toata munca depusa. Doamne cat am mai cautat ceva asemanator acum 2-3 ani in urma! (fara rezultate). Intre timp am reusit sa scriu si eu cateva microcontrolere, am invatat despre variabile, functii etc. traducand din engleza si testand. Engleza mea nefiind la un nivel suficient de avansat mi-a trebuit ceva transpiratie. Si cat de aerisit pare acum totul expus cu maestrie in limba mea materna! Am raspunsul la cateva neclaritati si astept cu nerabdare continuarile (abia astept sa ajungem la scriere/citirea in/din EEPROM :) ). 

Spuneai ca:

  1. [*]/*Declaram doua constante ON si OFF ca sa ne fie mai usor de inteles programul*/ [*]const unsigned char ON = 1; [*]const unsigned char OFF = 0;

 

In varianta finala aceste doua constante NU mai sunt definite. (ON si OFF sunt cuvinte cheie si compilatorul stie ce are de facut?)

Apoi, intr-un comentariu spui:

//variabila timp va scadea cu o unitate pentru fiecare 100ms care trec

Nu 10ms?! (Ramasita de la cautarile tale legate de temporizare)

Stiu ca aceste mici neconcordante NU afecteaza programul dar pot induce confuzii...

Inca odata mii de MULTUMIRI!

Link spre comentariu

Spuneai ca:

[*]/*Declaram doua constante ON si OFF ca sa ne fie mai usor de inteles programul*/

[*]const unsigned char ON = 1;

[*]const unsigned char OFF = 0;

 

In varianta finala aceste doua constante NU mai sunt definite. (ON si OFF sunt cuvinte cheie si compilatorul stie ce are de facut?)

Prin faptul ca am declarat aceste constante la inceptul functiei main(), ele sunt definite.

Iar ele sunt folosite in program atunci cand bitul RB0 este setat sau cleared (sters) prin expresiile: RB0_bit = ON; sau RB0_bit = OFF;

 

In acest caz ON si OFF sunt numele unor constante. 

Banuiesc la ce te referi, puteam sa folosesc directiva #define si de altfel eu asa si procedez doar ca nu am discutat despre acestea inca. Daca foloseam acea directiva atunci sigur, ON si OFF erau inlocuite de linker in momentul compilarii cu valorile 1 respectiv 0. Dar nu este cazul aici.

 

Apoi, intr-un comentariu spui:

//variabila timp va scadea cu o unitate pentru fiecare 100ms care trec

Nu 10ms?! (Ramasita de la cautarile tale legate de temporizare)

 

Corect. Unitatea de timp este de 10ms. Comentariul ar trebui modificat.

 

Stiu ca aceste mici neconcordante NU afecteaza programul dar pot induce confuzii...

Inca odata mii de MULTUMIRI!

 

Multumesc si eu pentru contributie!

Editat de mars01
Link spre comentariu

Va salut colegi forum-isti.
Asta este prima mea postare, desi urmaresc forumul de mult timp.
Subiectul acesta il urmaresc cu mare interes, poate se prinde si de mine ceva, desi ma tot chinui de ceva timp sa invat programarea PIC-urilor.
Doresc sa ii multumesc FOARTE mult d-lui mars01 ca pierde timpul cu explicatii nemaiintilnit de bine explicate.
Acum despre subiect.
La programul d-lui ciocanaru din postul #147:

void main() {
unsigned int timp = 6000;   /*variabila este initializata cu 6000 */
const unsigned int tempo = 6000;  /*constanta primeste valoarea 6000*/
 
/*Declaram doua constante ON si OFF ca sa ne fie mai usor de inteles programul*/
const unsigned char ON = 1;
const unsigned char OFF = 0;
/************** INITIALIZARE***************************/
CMCON = 0b00000111;  //dezactivam comparator
ADCON0 = 0;   //dezactivam ADC
ADCON1 = 0x6;   //facem toate intrarile analogice, digitale.
CVRCON = 0;   //dezactivam referinta variabila de tensiune
PIE1 = 0b00000000; //dezavtivam  "Parallel Slave Port" PSP (pag. 25 datasheets) Bit 7 == 0


TRISA = 0b00000001; //facem INTRARE din pinul2 adica RA0; aici vom avea switch-ul conectat
TRISB = 0b00000000; //facem IESIRE din toti pinii PORTB; aici vom avea releulul si LED-urile conectate
TRISD = 0b00011111; //facem IESIRE din pinii 28-30 ai PORTD, adica RD5-RD7; si aici vom avea LED-uri conectate
PORTB = 0b00000000; //pornim cu releul decuplat si LED-urile stinse
PORTD = 0b00000000; //pornim cu releul decuplat si LED-urile stinse
/**************SFARSIT INITIALIZARE********************/
  while(1){
 
  if(RA0_bit == 0){    
  delay_ms(10);    
if (RA0_bit == 0){    
RB0_bit = ON;  
RD5_bit = ON;  
while( 1 < timp <6000){    /*aici variabila timp este apelata prima oara, deci are valoarea 6000.
        Nu cumva iese din bucla? Sa presupunem ca o vom si egala cu 6000*/
if(RA0_bit == 0){  
delay_ms(10);  
  if(RA0_bit == 0){  
  timp = timp + tempo;    //daca este egalata, variabila timp = timp(6000) + tempo(6000) = 12000 ?
  RD6_bit = ON;    
  }
}
if(timp<6000){RD6_bit = OFF;}   //aici timp = 12000, se mai executa {RD6_bit = OFF;} ?

Daca nu am inteles pana aici, nu cred ca trebuie sa trec mai departe, atunci trebuie sa mai recitesc subiectul.

Inca o data mii de MULTUMIRI lui mars01, cat si celorlalti care contribuie la acest subiect.

Editat de AliBaba33
Link spre comentariu

@AliBaba33: eu zic sa nu te chinui sa intelegi ce s-a postat mai sus.

 

@ciocanaru: ce ai postat tu va merge perfect la sectiunea "cum NU trebuie conceput/scris un program" !

(daca mars01 are in gand sa trateze si asa ceva)

cred ca trebuie eliminat acest post. si revenit cu el la momentul ... potrivit.

Link spre comentariu
Vizitator ciocanaru

Da, sunt greseli si mi le-am asumat de la inceput. Din ele cred ca putem invata. Ce am postat este UN EXERCITIU si astept ca cei mai experimentati sa ma(ne) ajute sa-l corectam si sa-l intelegem.

Link spre comentariu

Cateva idei despre cum scriem un program:

 

- un program trebuie sa fie bine formatat

 

Este importanta folosirea tab-urilor pentru a evidentia grupuri de instructiuni care au sens impreuna. Este mult mai usor de citit un program care este bine indentat. Folosind tab-uri. Indentarea cu ajutorul unui spatiu (tasta SPACE) nu este suficienta pentru a genera usurinta in citire

 

- un program este bine sa fie impartit in functii.

 

Este mult mai usor cand lucram cu functii decat daca tot programul se gaseste "varsat" in functia principala, main(). Imaginati-va ca aveti foarte multe suruburi, sa zicem. Unele sunt M3, altele M4, altele M8, altele M12. Toate sunt folosite in acelasi proiect. Cand ai unul sau doua tipuri de suruburi, poti sa scapi relativ usor cand le ai puse toate intr-o cutie, faci economie la cutii si de ce nu, la spatiu ocupat. E un pic greu sa cauti in cutie ca sa gasesti ce te intereseaza, surubul cu dimensiunea dorita, dar nu e chiar asa o problema.

Dar atunci cand ai multe suruburi, est emult mai bine ca fiecare tip de surub sa fie pus in cutia lui. 

Este o metoda de organizare. Consuma mai mult spatiu, consuma resurse suplimentare (cutiile) dar per ansamblu este muuult mai usor de lucrat. De acord?

 

- un program este bine sa fie bine comentat

 

Trebuie gasit un compromis intre a comenta suficient si a comenta prea mult. Prea multe comentarii fac codul dificil de citit.

Comentati codul pentru ca o sa vedeti ca o sa va fie util chiar voua dupa ce trece o luna doua si nu ati mai lucrat la proiect intre timp. O sa uitati ce ati vrut sa faceti pe acolo. Si ce bine o sa va simtiti ca ati fost inspirati sa comentati !!!

 

Fiecare functie in parte trebuie bine comentata intr-un comentariu bloc (definit  "/* ...*/") aflat chiar inainte de corpul functiei sau la declaratie, dupa cum va vine mai usor.

Cand se folosesc asa numitele colectii de functii ("libraries"), functiile se comenteaza bine si foarte bine in fisierul header, cel cu extensia .h, unde se gasesc declaratiile functiilor din librarie.

 

Atunci cand doriti ca un program sa fie evaluat de catre alti colegi, este bine sa il formatati incat componentele sale logice sa fie bine definite, sa il faceti prezentabil si usor de citit pentru ca altfel nimeni nu sta sa il citeasca, daramite sa il interpreteze. Apoi comentati-l si spuneti care este intentia in urmatoarea sectiune de cod. Asa este usor pentru "review-uri" sa inteleaga ce ati vrut sa faceti si apoi sa va sugereze inbunatatiri sau corectii.

 

Cred ca mai sunt si alte aspecte dar acestea imi vin in minte acum.

Editat de mars01
Link spre comentariu

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 cont

Autentificare

Ai deja un cont? Autentifică-te aici.

Autentifică-te acum
×
×
  • Creează nouă...

Informații Importante

Am plasat cookie-uri pe dispozitivul tău pentru a îmbunătății navigarea pe acest site. Poți modifica setările cookie, altfel considerăm că ești de acord să continui.Termeni de Utilizare si Ghidări