iuli09 Postat Iunie 14, 2016 Partajează Postat Iunie 14, 2016 (editat) N-am pus chiar toate ledurile ...ca nu incap . Am pus vreo 10-12 din care jumatate nu raman aprinse . Am facut teste si cu doua , trei sau patru leduri . Pinii cu probleme s-au comportat la fel indiferent cate leduri am lasat conectate . Dar o sa incerc maine si cu rezistente sau tranzistori . Editat Iunie 14, 2016 de iuli09 Link spre comentariu
mars01 Postat Iunie 14, 2016 Partajează Postat Iunie 14, 2016 (editat) Incearca programul de blinking pe care l-am postat la postul #43. Daca si ala face probleme ... Editat Iunie 14, 2016 de mars01 Link spre comentariu
Vizitator Postat Iunie 14, 2016 Partajează Postat Iunie 14, 2016 (editat) Am modificat un pic programul lui mars01. Am folosit doar portile D, doua butoane, si este functional in PROTEUS. Nu am cum sa testez si pe breadbord (sunt in concediu), Codul ete acesta: // http://www.elforum.info/topic/112710-exercitii-programare-de-la-zero/page-3#entry1388462/*Declaram doua constante ON si OFF */#define ON 1#define OFF 0#define delay 100void lights_on() { RD0_bit = ON; //aprindem becul delay_ms(delay); // intarziere de o secunda RD1_bit = ON; delay_ms(delay); RD2_bit = ON; delay_ms(delay); RD3_bit = ON; delay_ms(delay); RD4_bit = ON; delay_ms(delay); RD5_bit = ON; delay_ms(delay); RD6_bit = ON; delay_ms(delay); RD7_bit = ON; delay_ms(delay); RD7_bit = ON; delay_ms(delay);}void lights_off() { RD0_bit = OFF; //Stingem becul delay_ms(delay); // intarziere de o secunda RD1_bit = OFF; delay_ms(delay); RD2_bit = OFF; delay_ms(delay); RD3_bit = OFF; delay_ms(delay); RD4_bit = OFF; delay_ms(delay); RD5_bit = OFF; delay_ms(delay); RD6_bit = OFF; delay_ms(delay); RD7_bit = OFF; delay_ms(delay);}void main() { unsigned char stare_lumini = OFF; // variabila care tine minte starea curenta a luminilor unsigned char last_RA0 = 1; // variabila care tine minte starea anterioara a butonului unsigned char last_RA1 = 1; /************** INITIALIZARE***************************/ //CMCON |= 7; ADCON0 = 0; //dezactivam ADC ADCON1 = 7; //port A and E pins are digital I/O TRISA = 0b00000011; //facem INTRARE din pinul 2 adica RA0, si pinul 3 adica RA1; aici vom avea doua butoane de conectat TRISD = 0b00000000; //RD 0-7 setati ca iesiri TRISE = 0b00000111; PORTD = 0b00000000; //pornim cu becurile de pe PORTD stinse /**************SFARSIT INITIALIZARE********************/ while(1) { if (RA0_bit == 1) last_RA0 = 1; if (RA0_bit == 0 && last_RA0 == 1) { //daca intrarea este LOW si luminile sunt oprite 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 if (stare_lumini == OFF) { lights_on(); stare_lumini = ON; } } last_RA0 = 0; } if (RA1_bit == 1) last_RA1 = 1; if (RA1_bit == 0 && last_RA1 == 1) { //daca intrarea este LOW si luminile sunt aprinse delay_ms(10); //asteptam 10 milisecunde if (RA1_bit == 0) { //daca intrarea inca mai este LOW atunci chiar ca avem o apasare reala de switch if (stare_lumini == ON) { lights_off(); stare_lumini = OFF; } } /*else { lights_off(); stare_lumini = OFF; }*/ last_RA1 = 0; } } } Editat Iunie 14, 2016 de Vizitator Link spre comentariu
iuli09 Postat Iunie 14, 2016 Partajează Postat Iunie 14, 2016 O sa incerc maine amandoua codurile ; totusi , in varianta finala vreau sa folosesc un singur buton cu revenire pentru comanda . Link spre comentariu
iuli09 Postat Iunie 15, 2016 Partajează Postat Iunie 15, 2016 17 LED-uri * 20 mA (sper ca ai pus si rezistori de limitare a curentului in serie cu fiecare LED) = 340 mA. S-ar putea sa fie prea mult pentru controller ... 5V*0.34A = 1.70W consum din chip. Si cred de aici este problema. Incearca sa limitezi curentul mai mult prin LED-uri. Foloseste rezistori serie cu fiecare LED de sa zicem cca 560 ... 680 ohmi sau foloseste tranzistori/IC_driver pentru comanda LED-urilor. Pana la urma aici a fost problema : am montat rezistente de limitare a curentului prin leduri si acum totul functioneaza asa cum trebuie . Nu mi-e foarte clar de ce a fost asta o problema dar pana la urma sunt multumit ca schema functioneaza si ca ma pot apuca efectiv de lucru . Am incercat si cu leduri , si cu relee si atata timp cat limitez curentul de iesire (cu sau fara tranzistori) montajul functioneaza . Va multumesc tuturor pentru ajutor . Link spre comentariu
mars01 Postat Iunie 15, 2016 Partajează Postat Iunie 15, 2016 Ma bucur sa vad ca sunt rezultate ... si ca lumea se misca usor usor Acum o lumina dinamica event-triggered, maine programare casa inteligenta Link spre comentariu
iuli09 Postat Iunie 15, 2016 Partajează Postat Iunie 15, 2016 Acum mi-a trecut prin cap ca ar fi fost interesant si un potentiometru din care sa reglez acea intarziere dintre actiunile de stingere/aprindere .Poate candva o sa reusesc sa fac si aceasta modificare .Pana atunci voi scrie cele 3 memorii cu 3 "intarzieri" diferite si o sa vad la fata locului care varianta imi place mai mult . Link spre comentariu
mars01 Postat Iunie 15, 2016 Partajează Postat Iunie 15, 2016 (editat) Mai intai o corectie. Nu stiu de ce dar intr-un post anterior, am avut impresia ca switch-ul este conecta pe RA2 si nu pe RA0 asa cum de altfel si era in design. De aceea, explicatiile subsecvente cu privire la posibilitatea registrului ADCON1 de a lua valori de 4, 5, 6 sau 7 au la baza faptul ca eu ma gandeam la RA2 ca fiind pin digital unde se monta switch-ul. Daca vrem ca pinul RA0 sa fie pin digital singurele variante posibile sunt ADCON1 = 6 sau ADCON1 = 7. mai exact situatia cand bitii PCFG2:PCFG0 sunt 11x (unde x nu conteaza). *********************************************************************************************** Acum, daca vrem sa alteram softul astfel incat sa putem schimba valoarea delay din potentiometru mai intai ne asiguram ca: - IMPORTANT: bifati libraria ADC in Library Manager al microC altfel vor fi erori la compilare. Menu: View - > Library Manager si bifati acolo ADC. - ADC-ul este ON deci in loc de ADCON0 = 0 scriem ori ADCON0 = 1 sau mai usor: ADON_bit = 1; Nota: s-ar putea sa fie redundant pentru ca probabil se face acelasi lucru in functia ADC_init() pe care trebuie sa o apelam in initializare - ne asiguram ca, sa zicem pinul RA1 (unde punem potentiometrul) este de data aceasta analogic. Din pacate nu avem nici-o situatie cand RA0 este digital si alt pin din portul A sa fie analogic. Vom alege prin urmare RA1 ca pin unde sa fie amplasat potentiometrul si RA2 pin unde sa fie plasat switch-ul (soarta, nu? ) Asadar, conform pozei de mai jos, alegem ADCON1 = 4 (combinatia 100 in binar inseamna 4 in decimal) - varianta 101 adica 5 nu este luata in considerare pentru ca presupune ca vom folosi o tensiuen de referinta alta decat VDD - ceea ce nu este cazul in situatia noastra. // alternativ se poate scrie ADCON1 = 0b00000100;ADCON1 = 4; - si facem din registrul TRISA pinii RA1 si RA2 intrari: TRISA = 0b00000110; Aceasta este partea de configurare. Programul se face asa (nu l-am verificat): /* Microcontroller PIC16F74 Switch pe pinul corespondent RA2 Potentiometru pe pinul corespondent RA1*/#define ON 1#define OFF 0unsigned int delay = 1000; // variabila care contine informatia cu privire la delay - val default 1000 msvoid lights_on() { RD2_bit = ON; //aprindem becul vdelay_ms(delay); // intarziere conform pozitie potentiometru RD3_bit = ON; vdelay_ms(delay); RC5_bit = ON; vdelay_ms(delay); RC6_bit = ON; vdelay_ms(delay); RC7_bit = ON; vdelay_ms(delay); RD4_bit = ON; vdelay_ms(delay); RD5_bit = ON; vdelay_ms(delay); RD6_bit = ON; vdelay_ms(delay); RD7_bit = ON; vdelay_ms(delay); RB0_bit = ON; vdelay_ms(delay); RB1_bit = ON; vdelay_ms(delay); RB2_bit = ON; vdelay_ms(delay); RB3_bit = ON; vdelay_ms(delay); RB4_bit = ON; vdelay_ms(delay); RB5_bit = ON; vdelay_ms(delay); RB6_bit = ON; vdelay_ms(delay); RB7_bit = ON; vdelay_ms(delay);}void lights_off() { RD2_bit = OFF; //Stingem becul vdelay_ms(delay); // intarziere conform pozitie potentiometru RD3_bit = OFF; vdelay_ms(delay); RC5_bit = OFF; vdelay_ms(delay); RC6_bit = OFF; vdelay_ms(delay); RC7_bit = OFF; vdelay_ms(delay); RD4_bit = OFF; vdelay_ms(delay); RD5_bit = OFF; vdelay_ms(delay); RD6_bit = OFF; vdelay_ms(delay); RD7_bit = OFF; vdelay_ms(delay); RB0_bit = OFF; vdelay_ms(delay); RB1_bit = OFF; vdelay_ms(delay); RB2_bit = OFF; vdelay_ms(delay); RB3_bit = OFF; vdelay_ms(delay); RB4_bit = OFF; vdelay_ms(delay); RB5_bit = OFF; vdelay_ms(delay); RB6_bit = OFF; vdelay_ms(delay); RB7_bit = OFF; vdelay_ms(delay);}//functie care va intoarce o valoare de la 0 la 2046unsigned int citire_delay() { unsigned int temp_value; unsigned short i; // facem o citire in ADC si pe urma o anulam. Este indicat ca prima citire sa nu fie luata in seama temp_value = ADC_read(1); temp_value = 0; for (i = 0; i < 10; i++) { temp_value = temp_value + ADC_Read(1); // RA1 care acum este de fapt AN1 este canalul 1 la ADC } temp_value = temp_value / 10; // facem medierea celor 10 citiri anterioare /* Inmultim valoarea cu 2 ca sa putem scoate o valoare de la 0 la 2046 ADC-ul pe 10 biti are o valoare maxima de 1023 dar daca introducem valoarea de 1023 direct in delay poate ca cca 1 secunda - adica 1023 ms - nu este suficient ca interval de reglare asa ca inmultim cu 2 Daca vreti inmultiti cu mai mult dar valoarea maxima sa fie temp_value * factor < 65535 (din cauza ca variabila este declarata ca fiind unsigned int). */ temp_value = temp_value * 2; // si intoarccem valoarea rezultata return temp_value;}void main() { unsigned char stare_lumini = OFF; // variabila care tine minte starea curenta a luminilor unsigned char last_RA2 = 1; // variabila care tine minte starea anterioara a butonului /************** INITIALIZARE***************************/ ADON_bit = 1; //activam ADC ADCON1 = 4; TRISA = 0b00000110; //facem INTRARE din RA1 si RA2; pe RA2 vom avea switch-ul conectat - pe RA1 potentiometrul TRISB = 0b00000000; //facem portul B B0-B7 ,iesire TRISC = 0b00011111; //RC 5-7 setati ca iesiri TRISD = 0b00000011; //RD 2-7 setati ca iesiri PORTB = 0b00000000; //pornim cu becurile de pe PORTB stinse PORTC = 0b00000000; //pornim cu becurile de pe PORTC stinse PORTD = 0b00000000; //pornim cu becurile de pe PORTD stinse ADC_Init(); //initializare ADC /**************SFARSIT INITIALIZARE********************/ while(1) { // apelam functia de citire a "delay-ului" la fiecare trecere prin bucla while(1) delay = citire_delay(); if (RA2_bit == 1) last_RA2 = 1; if (RA2_bit == 0 && last_RA2 == 1) { //daca intrarea RA2 este LOW si luminile sunt oprite delay_ms(10); //asteptam 10 milisecunde if (RA2_bit == 0) { //daca intrarea inca mai este LOW atunci chiar ca avem o apasare reala de switch if (stare_lumini == OFF) { lights_on(); stare_lumini = ON; } else { lights_off(); stare_lumini = OFF; } } last_RA2 = 0; } }} LE: Am mai schimbat cate una alta prin program (initial setasem ADCON1 incat ADC-ul avea nevoie de Vref externa, am mai schimbat prin comenturi). Atentie: functia delay_ms(x) cere ca parametru o constanta deci o valoare care nu se schimba. In schimb functia vdelay_ms(x) accepta o valoare variabila si de aceea a fost folosita in ultima versiune a program-ului. Editat Iunie 15, 2016 de mars01 Link spre comentariu
Mircea Postat Iunie 15, 2016 Partajează Postat Iunie 15, 2016 P-asta cu VDelay nu o stiam. Multumesc.Clar, trebuie sa mai deschid help-ul din cand in cand. Link spre comentariu
mars01 Postat Iunie 15, 2016 Partajează Postat Iunie 15, 2016 Si eu am aflat-o tot pe aici pana atunci faceam for-uri cu delay_ms() ... Link spre comentariu
Mircea Postat Iunie 15, 2016 Partajează Postat Iunie 15, 2016 Si eu la fel...Ai testat deja cum variaza cu durata? Caci Help-ul zice ca nu e cea mai precisa. Link spre comentariu
mars01 Postat Iunie 15, 2016 Partajează Postat Iunie 15, 2016 (editat) Nu Mircea, nu am testat, pentru ca oricum pentru chestii de precizie ma folosesc de timere si intreruperi. Urmatorul program face exact acelasi lucru ca si cel de dinainte doar ca folosesc un microcontroler 12F675 care are disponibili doar 5 pini I/O din care unul poate fi numai intrare (GP3). Pentru a obtine pana la 32 de iesiri ma folosesc de 4 registri 74HC595. Atentie, pinii lui 74HC595 pot furniza numai 8mA pe fiecare pin deci sunt necesari rezistori corespunzatori de limitare a curentului in serie cu eventualele LED-uri sau folositi drivere pentru LED-uri, bec-uri sau mai stiu eu ce. Am sa il folosesc ca platforma de explicatii pentru ce o sa scriu in continuare in topicul: http://www.elforum.info/topic/111858-invatat-programare-de-la-zero/ Schema este urmatoarea: iar programul este acesta: /* Microcontroller PIC 12F675 Switch pe pinul corespondent GP3 Potentiometru pe pinul corespondent GP4/AN3 - canalul 3 al ADC Pin LATCH de la toti HC595 pe GP0 Pin CLOCK de la toti HC595 pe GP1 Pin DATA de la primul HC595 din cei 4 registri, pe GP2*/#define ON 0#define OFF 1#define INPUT 1#define OUTPUT 0#define SW GP3_bit // aici conectam switch-ul#define SW_DIR TRISIO3_bit#define LATCH GP0_bit // aici conectam pinul LATCH de la toti cei 4 registri HC595#define CLK GP1_bit // aici conectam pinul CLOCK de la toti cei 4 registri HC595#define DATA GP2_bit // aici conectam pinul DATA de la primul registru HC595#define LATCH_DIR TRISIO0_bit#define CLK_DIR TRISIO1_bit#define DATA_DIR TRISIO2_bit#define NR_LED 17 // numarul nu poate fi mai mare de 32 LED-uriunsigned int delay = 1000; // variabila care contine informatia cu privire la delay - val default 1000 ms/* O mica explicatie: Variabila valoare_iesire este tip unsigned LONG. Fiind LONG ea va avea alocati 4 bytes adica 32biti. Variabila imediat urmatoare (in sens descendent) ca numar de bytes este cea cu tipul INT care are alocati 2 bytes adica 16 biti. Noi avem 17 LED-uri deci avem nevoie de 17 biti, pe fiecare bit vom stoca starea cate unui LED. Cum 16 biti sunt prea putini, vom folosi tipul LONG care ne ofera posibilitatea de a avea 17 biti pentru 17 LED-uri (sigur, vom putea adauga pana la 32 de LED-uri pentru ca avem 32 de biti in variabila. Continutul variabilei valoare_iesire va fi trimis in mod serial catre setul de 3 registri 74HC595 necesari. De fapt am pus 4 registri pana la urma.*/unsigned long valoare_iesire = 0;//functie care va intorce o valoare de la 0 la 2048 functie de pozitia unui potentiometru conectat pe canalul 3 al ADCunsigned int citire_delay() { unsigned int temp_value; unsigned short i; // facem o citire in ADC si pe urma o anulam. Este indicat ca prima citire sa nu fie luata in seama temp_value = ADC_read(3); temp_value = 0; for (i = 0; i < 10; i++) { temp_value = temp_value + ADC_Read(3); // RA1 care acum este de fapt AN1 este canalul 1 la ADC } temp_value = temp_value / 10; // facem medierea celor 10 citiri anterioare /* Inmultim valoarea cu 2 ca sa putem scoate o valoare de la 0 la 2046 ADC-ul pe 10 biti are o valoare maxima de 1023 dar daca introducem valoarea de 1023 direct in delay poate ca cca 1 secunda - adica 1023 ms - nu este suficient ca interval de reglare asa ca inmultim cu 2 Daca vreti inmultiti cu mai mult dar valoarea maxima sa fie temp_value * factor < 65535 (din cauza ca variabila este declarata ca fiind unsigned int). */ temp_value = temp_value * 2; // si intoarccem valoarea rezultata return temp_value;}void HC595(unsigned long val) { unsigned short i; // contor ciclu for LATCH = 0; // ne asiguram ca pinii HC595 sunt izolati de orice modificari pana cand suntem gata CLK = 0; // clock-ul este LOW for (i = 0; i< 32; i++) { // 0x80000000 este totuna cu 0b10000000 00000000 00000000 00000000 adica fix 32 biti // verificam tot timpul acest bit daca este 1 sau 0 if (val & 0x80000000uL) DATA = 1; else DATA = 0; // trimitem informatia pe pinul DATA prin urmatoare secventa pe pinul CLK // trimitem tot timpul bitul cel mai semnificativ, adica cel mai din stanga, adica al 32 lea // prin shiftare la stanga, unul cate unul, ii vom trimite pe toti 32 // evident toti cei din stanga bitului 17 vor fi 0 pentru ca nu ne intereseaza CLK = 1; CLK = 0; // shiftam datele la stanga o pozitie pentru testare urmatorul bit val = val << 1; } // actualizam informatia din registrii HC595 pe pinii acestora LATCH = 1;}void lights_on(){ unsigned short i; // contor ciclu for valoare_iesire = 0; for (i = 0; i < NR_LED; i++) { valoare_iesire = ((valoare_iesire << 1) | 1); // shiftam la stanga si pe urma adaugam un 1 pe ultima pozitie HC595(valoare_iesire); vdelay_ms(delay); }}void lights_off(){ unsigned int i; // contor ciclu for valoare_iesire = 0b11111111111111111; for ( i = 0; i < NR_LED; i++) { valoare_iesire = ((valoare_iesire << 1) & 0xFFFFFFFE); // shiftam la stanga si pe urma adaugam un 0 pe ultima pozitie HC595(valoare_iesire); vdelay_ms(delay); }}void main() { unsigned char stare_lumini = 0; // variabila care tine minte starea curenta a luminilor unsigned char last_SW = 1; // variabila care tine minte starea anterioara a butonului /************** INITIALIZARE***************************/ CMCON = 7; // disable comparator ANS3_bit = 1; // AN3 este analog pin ANS2_bit = 0; // AN2 este digital pin ANS1_bit = 0; // AN1 este digital pin ANS0_bit = 0; // AN0 este digital pin SW_DIR = INPUT; LATCH_DIR = OUTPUT; CLK_DIR = OUTPUT; DATA_DIR = OUTPUT; // starea default este LOW LATCH = 0; CLK = 0; DATA= 0; ADC_Init(); //initializare ADC /**************SFARSIT INITIALIZARE********************/ // executam o data functia HC595 ca sa ne asiguram ca toate LED-urile sunt OFF, trimitand valoarea 0 HC595(0); while(1) { // apelam functia de citire a "delay-ului" la fiecare trecere prin bucla while(1) delay = citire_delay(); if (SW == ON) last_SW = ON; if (SW == ON && last_SW == ON) { //daca intrarea RA2 este LOW si luminile sunt oprite delay_ms(10); //asteptam 10 milisecunde if (SW == ON) { //daca intrarea inca mai este LOW atunci chiar ca avem o apasare reala de switch if (stare_lumini == 0) { lights_on(); stare_lumini = 1; } else { lights_off(); stare_lumini = 0; } } last_SW = 0; } }} Editat Iunie 15, 2016 de mars01 Link spre comentariu
Vizitator Postat Iunie 16, 2016 Partajează Postat Iunie 16, 2016 (editat) Am probat si eu acest cod al lui mars01, cu putine modificari, pentru 32 de LED-uri. // #define NR_LED 17 // numarul nu poate fi mai mare de 32 LED-uri#define NR_LED 32 // numarul nu poate fi mai mare de 32 LED-uri...// valoare_iesire = 0b11111111111111111; // nr LED-uri 17valoare_iesire = 0b111111111111111111111111111111; // nr LED-uri 32 . Editat Iunie 16, 2016 de Vizitator Link spre comentariu
mars01 Postat Iunie 16, 2016 Partajează Postat Iunie 16, 2016 (editat) La cum merge programul acum de fapt nici nu este necesara prezenta in functia lights_off() a liniei: // valoare_iesire = 0b11111111111111111; // nr LED-uri 17 Dar cine stie ce modificari se mai fac la program asa ca este bine sa aiba o valoare de pornire bine definita. ******************************************************* Iata si o varianta a programului care este facuta sa fie usor de portat pe un alt compilator (de ex XC8). Varianta pentru compilatorul mikroC for PIC: ATENTIE: se compileaza fara nici-o librarie a mikroC bifata. Functiile de initializare si citire a ADC sunt definite in program ... /* Microcontroller PIC 12F675 Switch pe pinul corespondent GP3 Potentiometru pe pinul corespondent GP4/AN3 - canalul 3 al ADC Pin LATCH de la toti HC595 pe GP0 Pin CLOCK de la toti HC595 pe GP1 Pin DATA de la primul HC595 din cei 4 registri, pe GP2*/#define INPUT 1#define OUTPUT 0#define SW GP3_bit // aici conectam switch-ul#define SW_DIR TRISIO3_bit#define ADC_DIR TRISIO4_bit // bitul pentru setare ca intrare a "intrarii analogice" - cea cu potentiometrul#define LATCH GP0_bit // aici conectam pinul LATCH de la toti cei 4 registri HC595#define CLK GP1_bit // aici conectam pinul CLOCK de la toti cei 4 registri HC595#define DATA GP2_bit // aici conectam pinul DATA de la primul registru HC595#define LATCH_DIR TRISIO0_bit#define CLK_DIR TRISIO1_bit#define DATA_DIR TRISIO2_bit#define NR_LED 17 // numarul nu poate fi mai mare de 32 LED-uri#define delay_func_ms(x) delay_ms(x)#define delay_func_us(x) delay_us(x)unsigned int delay = 1000; // variabila care contine informatia cu privire la delay - val default 1000 msenum { ON = 0, OFF = 1};/* O mica explicatie: Variabila valoare_iesire este tip unsigned LONG. Fiind LONG ea va avea alocati 4 bytes adica 32biti. Variabila imediat urmatoare (in sens descendent) ca numar de bytes este cea cu tipul INT care are alocati 2 bytes adica 16 biti. Noi avem 17 LED-uri deci avem nevoie de 17 biti, pe fiecare bit vom stoca starea cate unui LED. Cum 16 biti sunt prea putini, vom folosi tipul LONG care ne ofera posibilitatea de a avea 17 biti pentru 17 LED-uri (sigur, vom putea adauga pana la 32 de LED-uri pentru ca avem 32 de biti in variabila. Continutul variabilei valoare_iesire va fi trimis in mod serial catre setul de 3 registri 74HC595 necesari. De fapt am pus 4 registri.*/unsigned long valoare_iesire = 0;// o practica buna este sa declaram functiile inainte de a le defini - unele compilatoare nu te lasa fara / mikroC este mai iertator :)unsigned int citire_delay();void HC595(unsigned long);void lights_on();void lights_off();void ADC_init();unsigned int ADC_read(unsigned short);//functie care va intorce o valoare de la 0 la 2048 in functie de pozitia unui pot conectat pe canalul 3 al ADCunsigned int citire_delay() { unsigned int temp_value; unsigned short i; // facem o citire in ADC si pe urma o anulam. Este indicat ca prima citire sa nu fie luata in seama temp_value = ADC_read(3); temp_value = 0; for (i = 0; i < 10; i++) { temp_value = temp_value + ADC_read(3); // RA1 care acum este de fapt AN1 este canalul 1 la ADC } temp_value = temp_value / 10; // facem medierea celor 10 citiri anterioare /* Inmultim valoarea cu 2 ca sa putem scoate o valoare de la 0 la 2046 ADC-ul pe 10 biti are o valoare maxima de 1023 dar daca introducem valoarea de 1023 direct in delay poate ca cca 1 secunda - adica 1023 ms - nu este suficient ca interval de reglare asa ca inmultim cu 2 Daca vreti inmultiti cu mai mult dar valoarea maxima sa fie temp_value * factor < 65535 (din cauza ca variabila este declarata ca fiind unsigned int). */ temp_value = temp_value * 2; // si intoarccem valoarea rezultata return temp_value;}void HC595(unsigned long val) { unsigned short i; // contor ciclu for LATCH = 0; // ne asiguram ca pinii HC595 sunt izolati de orice modificari pana cand suntem gata CLK = 0; // clock-ul este LOW for (i = 0; i< 32; i++) { // 0x80000000 este totuna cu 0b10000000 00000000 00000000 00000000 adica fix 32 biti // verificam tot timpul acest bit daca este 1 sau 0 if (val & 0x80000000uL) DATA = 1; else DATA = 0; // trimitem informatia pe pinul DATA prin urmatoare secventa pe pinul CLK // trimitem tot timpul bitul cel mai semnificativ, adica cel mai din stanga, adica al 32 lea // prin shiftare la stanga, unul cate unul, ii vom trimite pe toti 32 // evident toti cei din stanga bitului 17 vor fi 0 pentru ca nu ne intereseaza CLK = 1; CLK = 0; // shiftam datele la stanga o pozitie pentru testare urmatorul bit val = val << 1; } // actualizam informatia din registrii HC595 pe pinii acestora LATCH = 1;}void lights_on(){ unsigned short i; // contor ciclu for unsigned int j; // contor ciclu for pentru delay valoare_iesire = 0; for (i = 0; i < NR_LED; i++) { valoare_iesire = ((valoare_iesire << 1) | 1); // shiftam la stanga si pe urma adaugam un 1 pe ultima pozitie HC595(valoare_iesire); for (j = 0; j < delay; j++){ delay_func_ms(1); } }}void lights_off(){ unsigned short i; // contor ciclu for unsigned int j; // contor ciclu for pentru delay valoare_iesire = 0b11111111111111111; for ( i = 0; i < NR_LED; i++) { valoare_iesire = ((valoare_iesire << 1) & 0xFFFFFFFE); // shiftam la stanga si pe urma adaugam un 0 pe ultima pozitie HC595(valoare_iesire); for (j = 0; j < delay; j++){ delay_func_ms(1); } }}void ADC_init() { // Facem bitii 6:4 = 111 adica selectam frecventa de conversie Frc ANSEL = ANSEL | 0b01110000; /* Result right justified Pos. reference voltage VDD */ ADCON0 = ADCON0 | 0b10000000; ADRESL = 0; ADRESH = 0;}unsigned int ADC_read(unsigned short channel) { // selectam canalul ADC ADCON0 = ADCON0 |(channel << 2); // pornim ADC-ul prin setarea bitului B0 adica cel numit ADON ADCON0 = ADCON0 | 0b00000001; delay_func_us(30); // 30 microsecunde este ceva mai mult de 11.5 us * 4 us; este timpul necesar pt conversie // pornim conversia ADC prin setarea bitului B1 adica cel numit GO/nDONE ADCON0 = ADCON0 | 0b00000010; // cat timp bitul GO/nDONE este inca 1 conversia nu s-a terminat, deci asteptam // cand conversia ADC se termina bitul GO/nDONE devine 0 si putem sa mergem mai departe while (ADCON0 & 0x02); // in acest moment conversia s-a terminat si putem sa citim valoarea convertita care se gaseste in cei doi registri: ADRESH si ADRESL return ((ADRESH << 8) + ADRESL);}void main() { unsigned char stare_lumini = 0; // variabila care tine minte starea curenta a luminilor unsigned char last_SW = 1; // variabila care tine minte starea anterioara a butonului /************** INITIALIZARE***************************/ CMCON = 7; // disable comparator // setam (adica il facem 1) bitul 3 // in acest fel, finndca bitul 3 este 1, AN3 devine pin analogic (se dezactiveaza toate chestiile digitale care mai sunt pe acel pin) // restul sunt digitali ANSEL = 0b00001000; // desi putem scapa usor nefacand nici-o modificare in TRISIO (default pinii sunt intrari) mai bine sa facem pinul GP3/AN3 intrare // pentru a ne obisnui sa lucram corect // asadar setam bitul TRISIO4 pentru a face din pinul AN3 nu doar analogic, dar si intrare analogica (nu este gresit, TRISIO4 corespunde pinului GP4/AN3) ADC_DIR = INPUT; SW_DIR = INPUT; LATCH_DIR = OUTPUT; CLK_DIR = OUTPUT; DATA_DIR = OUTPUT; // starea default este LOW LATCH = 0; CLK = 0; DATA= 0; ADC_init(); //initializare ADC /**************SFARSIT INITIALIZARE********************/ // executam o data functia HC595 ca sa ne asiguram ca toate LED-urile sunt OFF, trimitand valoarea 0 HC595(0); while(1) { // apelam functia de citire a "delay-ului" la fiecare trecere prin bucla while(1) delay = citire_delay(); if (SW == ON) last_SW = ON; if (SW == ON && last_SW == ON) { //daca intrarea RA2 este LOW si luminile sunt oprite delay_func_ms(10); //asteptam 10 milisecunde if (SW == ON) { //daca intrarea inca mai este LOW atunci chiar ca avem o apasare reala de switch if (stare_lumini == 0) { lights_on(); stare_lumini = 1; } else { lights_off(); stare_lumini = 0; } } last_SW = 0; } }} Iar pentru portarea in compilatorul XC8 se modifica doar in #define-urile de la inceput (plus configurarea in clar a registrilor CONFIG cu pragma config - la mikroC se fac in mod vizual, intr-o fereastra; evident se include si xc.h si se declara ce frecventa se foloseste pentru a-i servi functiei __delay_ms). #include <xc.h>#define _XTAL_FREQ 4000000// CONFIG#pragma config FOSC = INTRCIO // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)#pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled)#pragma config PWRTE = OFF // Power-Up Timer Enable bit (PWRT disabled)#pragma config MCLRE = OFF // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)#pragma config BOREN = OFF // Brown-out Detect Enable bit (BOD disabled)#pragma config CP = OFF // Code Protection bit (Program Memory code protection is disabled)#pragma config CPD = OFF // Data Code Protection bit (Data memory code protection is disabled)/* Microcontroller PIC 12F675 Switch pe pinul corespondent GP3 Potentiometru pe pinul corespondent GP4/AN3 - canalul 3 al ADC Pin LATCH de la toti HC595 pe GP0 Pin CLOCK de la toti HC595 pe GP1 Pin DATA de la primul HC595 din cei 4 registri, pe GP2*/#define INPUT 1#define OUTPUT 0#define SW GPIObits.GP3 // aici conectam switch-ul#define SW_DIR TRISIObits.TRISIO3#define ADC_DIR TRISIObits.TRISIO4 // aici este conectat potentiometrul#define LATCH GPIObits.GP0 // aici conectam pinul LATCH de la toti cei 4 registri HC595#define CLK GPIObits.GP1 // aici conectam pinul CLOCK de la toti cei 4 registri HC595#define DATA GPIObits.GP2 // aici conectam pinul DATA de la primul registru HC595#define LATCH_DIR TRISIObits.TRISIO0#define CLK_DIR TRISIObits.TRISIO1#define DATA_DIR TRISIObits.TRISIO2#define NR_LED 17 // numarul nu poate fi mai mare de 32 LED-uri#define delay_func_ms(x) __delay_ms(x)#define delay_func_us(x) __delay_us(x)unsigned int delay = 1000; // variabila care contine informatia cu privire la delay - val default 1000 msenum { ON = 0, OFF = 1};/* O mica explicatie: Variabila valoare_iesire este tip unsigned LONG. Fiind LONG ea va avea alocati 4 bytes adica 32biti. Variabila imediat urmatoare (in sens descendent) ca numar de bytes este cea cu tipul INT care are alocati 2 bytes adica 16 biti. Noi avem 17 LED-uri deci avem nevoie de 17 biti, pe fiecare bit vom stoca starea cate unui LED. Cum 16 biti sunt prea putini, vom folosi tipul LONG care ne ofera posibilitatea de a avea 17 biti pentru 17 LED-uri (sigur, vom putea adauga pana la 32 de LED-uri pentru ca avem 32 de biti in variabila. Continutul variabilei valoare_iesire va fi trimis in mod serial catre setul de 3 registri 74HC595 necesari. De fapt am pus 4 registri.*/unsigned long valoare_iesire = 0;// o practica buna este sa declaram functiile inainte de a le defini - unele compilatoare nu te lasa fara / mikroC este mai iertator :)unsigned int citire_delay();void HC595(unsigned long);void lights_on();void lights_off();void ADC_init();unsigned int ADC_read(unsigned short);//functie care va intorce o valoare de la 0 la 2048 in functie de pozitia unui pot conectat pe canalul 3 al ADCunsigned int citire_delay() { unsigned int temp_value; unsigned short i; // facem o citire in ADC si pe urma o anulam. Este indicat ca prima citire sa nu fie luata in seama temp_value = ADC_read(3); temp_value = 0; for (i = 0; i < 10; i++) { temp_value = temp_value + ADC_read(3); // RA1 care acum este de fapt AN1 este canalul 1 la ADC } temp_value = temp_value / 10; // facem medierea celor 10 citiri anterioare /* Inmultim valoarea cu 2 ca sa putem scoate o valoare de la 0 la 2046 ADC-ul pe 10 biti are o valoare maxima de 1023 dar daca introducem valoarea de 1023 direct in delay poate ca cca 1 secunda - adica 1023 ms - nu este suficient ca interval de reglare asa ca inmultim cu 2 Daca vreti inmultiti cu mai mult dar valoarea maxima sa fie temp_value * factor < 65535 (din cauza ca variabila este declarata ca fiind unsigned int). */ temp_value = temp_value * 2; // si intoarccem valoarea rezultata return temp_value;}void HC595(unsigned long val) { unsigned short i; // contor ciclu for LATCH = 0; // ne asiguram ca pinii HC595 sunt izolati de orice modificari pana cand suntem gata CLK = 0; // clock-ul este LOW for (i = 0; i< 32; i++) { // 0x80000000 este totuna cu 0b10000000 00000000 00000000 00000000 adica fix 32 biti // verificam tot timpul acest bit daca este 1 sau 0 if (val & 0x80000000uL) DATA = 1; else DATA = 0; // trimitem informatia pe pinul DATA prin urmatoare secventa pe pinul CLK // trimitem tot timpul bitul cel mai semnificativ, adica cel mai din stanga, adica al 32 lea // prin shiftare la stanga, unul cate unul, ii vom trimite pe toti 32 // evident toti cei din stanga bitului 17 vor fi 0 pentru ca nu ne intereseaza CLK = 1; CLK = 0; // shiftam datele la stanga o pozitie pentru testare urmatorul bit val = val << 1; } // actualizam informatia din registrii HC595 pe pinii acestora LATCH = 1;}void lights_on(){ unsigned short i; // contor ciclu for unsigned int j; // contor ciclu for pentru delay valoare_iesire = 0; for (i = 0; i < NR_LED; i++) { valoare_iesire = ((valoare_iesire << 1) | 1); // shiftam la stanga si pe urma adaugam un 1 pe ultima pozitie HC595(valoare_iesire); for (j = 0; j < delay; j++){ delay_func_ms(1); } }}void lights_off(){ unsigned short i; // contor ciclu for unsigned int j; // contor ciclu for pentru delay valoare_iesire = 0b11111111111111111; for ( i = 0; i < NR_LED; i++) { valoare_iesire = ((valoare_iesire << 1) & 0xFFFFFFFE); // shiftam la stanga si pe urma adaugam un 0 pe ultima pozitie HC595(valoare_iesire); for (j = 0; j < delay; j++){ delay_func_ms(1); } }}void ADC_init() { // Facem bitii 6:4 = 111 adica selectam frecventa de conversie Frc ANSEL = ANSEL | 0b01110000; /* Result right justified Pos. reference voltage VDD */ ADCON0 = ADCON0 | 0b10000000; ADRESL = 0; ADRESH = 0;}unsigned int ADC_read(unsigned short channel) { // selectam canalul ADC ADCON0 = ADCON0 |(channel << 2); // pornim ADC-ul prin setarea bitului B0 adica cel numit ADON ADCON0 = ADCON0 | 0b00000001; delay_func_us(30); // 30 microsecunde este ceva mai mult de 11.5 us * 4 us; este timpul necesar pt conversie // pornim conversia ADC prin setarea bitului B1 adica cel numit GO/nDONE ADCON0 = ADCON0 | 0b00000010; // cat timp bitul GO/nDONE este inca 1 conversia nu s-a terminat, deci asteptam // cand conversia ADC se termina bitul GO/nDONE devine 0 si putem sa mergem mai departe while (ADCON0 & 0x02); // in acest moment conversia s-a terminat si putem sa citim valoarea convertita care se gaseste in cei doi registri: ADRESH si ADRESL return ((ADRESH << 8) + ADRESL);}void main() { unsigned char stare_lumini = 0; // variabila care tine minte starea curenta a luminilor unsigned char last_SW = 1; // variabila care tine minte starea anterioara a butonului /************** INITIALIZARE***************************/ CMCON = 7; // disable comparator // setam (adica il facem 1) bitul 3 // in acest fel, finndca bitul 3 este 1, AN3 devine pin analogic (se dezactiveaza toate chestiile digitale care mai sunt pe acel pin) // restul sunt digitali ANSEL = 0b00001000; // desi putem scapa usor nefacand nici-o modificare in TRISIO (default pinii sunt intrari) mai bine sa facem pinul GP3/AN3 intrare // pentru a ne obisnui sa lucram corect // asadar setam bitul TRISIO4 pentru a face din pinul AN3 nu doar analogic, dar si intrare analogica (nu este gresit, TRISIO4 corespunde pinului GP4/AN3) ADC_DIR = INPUT; SW_DIR = INPUT; LATCH_DIR = OUTPUT; CLK_DIR = OUTPUT; DATA_DIR = OUTPUT; // starea default este LOW LATCH = 0; CLK = 0; DATA= 0; ADC_init(); //initializare ADC /**************SFARSIT INITIALIZARE********************/ // executam o data functia HC595 ca sa ne asiguram ca toate LED-urile sunt OFF, trimitand valoarea 0 HC595(0); while(1) { // apelam functia de citire a "delay-ului" la fiecare trecere prin bucla while(1) delay = citire_delay(); if (SW == ON) last_SW = ON; if (SW == ON && last_SW == ON) { //daca intrarea RA2 este LOW si luminile sunt oprite delay_func_ms(10); //asteptam 10 milisecunde if (SW == ON) { //daca intrarea inca mai este LOW atunci chiar ca avem o apasare reala de switch if (stare_lumini == 0) { lights_on(); stare_lumini = 1; } else { lights_off(); stare_lumini = 0; } } last_SW = 0; } }} Editat Iunie 16, 2016 de mars01 Link spre comentariu
Vizitator Postat Iunie 16, 2016 Partajează Postat Iunie 16, 2016 (editat) Am incercat codul din postarea anterioara in mikroC dar am aceasta eroare: Editat Iunie 16, 2016 de Vizitator 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