mars01 Postat Octombrie 24, 2017 Partajează Postat Octombrie 24, 2017 LED-ul face blink? Link spre comentariu
catalin004 Postat Octombrie 24, 2017 Autor Partajează Postat Octombrie 24, 2017 nu.... Link spre comentariu
mars01 Postat Octombrie 24, 2017 Partajează Postat Octombrie 24, 2017 Era o intrebare retorica ... mai degraba un hint de unde sa apuci problema. In ce sectiune a programului se decide ca LED-ul sa faca blink la 500ms? Cine face acea temporizare? Link spre comentariu
catalin004 Postat Octombrie 24, 2017 Autor Partajează Postat Octombrie 24, 2017 (editat) LED-ul cred ca ar trebui sa faca blink in 500ms odata cu flag=1....adica in interrupt trebuia pus RA=!RA.... Editat Octombrie 24, 2017 de catalin004 Link spre comentariu
mars01 Postat Octombrie 24, 2017 Partajează Postat Octombrie 24, 2017 (editat) Nu e din cauza aceasta. Merge si cum spui tu doar ca sunt cateva operatii in plus care se fac in intrerupere lucru pe care trebuei sa il eviti cat poti. Functia rulata de intrerupere trebuie sa fie cat mai scurta. Dar repet, merge si cum spui tu. Doar ca lipseste ceva .... Ruleaza programul de mai jos si incearca sa vezi unde sta diferenta /* Compiler = mikroC 7.1.0 uC type = 16F876A uC freq = 4MHz uC Datasheet = http://ww1.microchip.com/downloads/en/DeviceDoc/39582b.pdf Author = mars01, on elforum.ro */ sbit LCD_RS at RB4_bit; sbit LCD_EN at RB5_bit; sbit LCD_D4 at RB0_bit; sbit LCD_D5 at RB1_bit; sbit LCD_D6 at RB2_bit; sbit LCD_D7 at RB3_bit; sbit LCD_RS_Direction at TRISB4_bit; sbit LCD_EN_Direction at TRISB5_bit; sbit LCD_D4_Direction at TRISB0_bit; sbit LCD_D5_Direction at TRISB1_bit; sbit LCD_D6_Direction at TRISB2_bit; sbit LCD_D7_Direction at TRISB3_bit; volatile unsigned int period = 0; volatile unsigned char display_flag = 0; unsigned char text[6]; // enough space for 5 characters // those are declared as volatile otherwise are optimized out by the compiler volatile unsigned int start = 0; volatile unsigned int stop = 0; // function prototype - declaration unsigned int period_func (unsigned int, unsigned int); void hw_init(); // function definition unsigned int period_func (unsigned int start_value, unsigned int stop_value){ return (stop_value - start_value); } void Interrupt(){ static unsigned int cnt = 0; static unsigned char flag = 0; if (CCP1IF_bit && CCP1IE_bit){ CCP1IF_bit = 0; // Reset CCP1 Interrupt period if (flag){ stop = (((unsigned int)CCPR1H)<< 8) | ((unsigned int)(CCPR1L)); // actual function usage (call) period = period_func(start, stop); flag = 0; // Reset Timer1 TMR1L = 0x00; TMR1H = 0x00; } else{ flag = 1; start = (((unsigned int)CCPR1H)<< 8) | ((unsigned int)(CCPR1L)); } } if (TMR0IF_bit && TMR0IE_bit){ // reset Timer0 TMR0IF_bit = 0; TMR0 = 0x06; // frequency will be displayed once every 500ms - twice per second if (cnt >= 500){ display_flag = 1; cnt = 0; } else{ cnt++; } } } // definitation of the hw_init() function which manage the HW initialization void hw_init(){ // Blink a LED to serve as a heart beat CMCON = 0x07; // comparators are OFF TRISA0_bit = 0; // RA0 is output; ADCON1 = 0xFF; // all pins are DIGITAL RA0_bit = 0; // RA0 start as OFF; // Configure CCP1 CCP1CON = 0b00000101; // capture mode every rising edge CCP1IF_bit = 0; // CCP1 interrupt flag - needs to be cleared in sw // Configure Timer1 T1CKPS1_bit = 0; // Timer1 prescaler set to 1:1; increment each 1us T1CKPS0_bit = 0; T1OSCEN_bit = 0; // LP oscillator is OFF TMR1CS_bit = 0; // TMR1 is incremented on internal clock TMR1ON_bit = 1; // enable Timer1 // Configure Timer0: Prescaler 1:4 and TMR0 preload with 0x06 PS2_bit = 0; // Prescaler configured at 1:4 PS1_bit = 0; PS0_bit = 1; NOT_RBPU_bit = 1; // pull-ups on Port B are disabled T0CS_bit = 0; // use internal instruction cycle clock PSA_bit = 0; // prescaler assigned to Timer0 TMR0 = 0x06; // preload the TMR0 register, combined with the prescaler value will give a 1ms interrupt // Initialize working registers TMR1L = 0x00; // Set Timer1 register to zero TMR1H = 0x00; CCPR1L = 0x00; // Initialize CCP register to 0 CCPR1H = 0x00; CCP1IE_bit = 1; // enable CCP1 interrupt TMR1IE_bit = 0; // disable TMR1 interrupt TMR0IE_bit = 1; // enable TMR0 interrupt // General enable of the interrupts GIE_bit = 1; // enable all interrupts PEIE_bit = 1; // enable peripheral interrupts LCD_init(); // initialize LCD Lcd_Cmd(_LCD_CLEAR); // Clear display Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off } void main(){ volatile unsigned long temp = 0; // volatile because otherwise it gets optimized out by the compiler // actual usage of our function that manage the hardware initialization hw_init(); Lcd_Out(1,1,"Frecventa: "); // display some static text, it will not change, on line 1 of the LCD while (1){ if (display_flag){ // if the time to display values has come (500ms passed) display_flag = 0; // make sure that you clear the flag so it is HIGH only when decided in the interrupt // LED heart beat RA0_bit = !RA0_bit; temp = 1000000 / period; // convert period (measured in microseconds) in frequency temp = temp * 60; // we get RPM value (rotation per minute) out of the frequency (rotations per second) WordToStr(temp, text); // convert RPM value to text string Lcd_Out(2,1, text); // display the text on LCD on line 2 } } } Editat Octombrie 24, 2017 de mars01 Link spre comentariu
catalin004 Postat Octombrie 24, 2017 Autor Partajează Postat Octombrie 24, 2017 (editat) Nu era initializat registrul interrupt TMR0 , cel care face afisarea si blinking... Editat Octombrie 24, 2017 de catalin004 Link spre comentariu
mars01 Postat Octombrie 24, 2017 Partajează Postat Octombrie 24, 2017 (editat) Te-ai prins. Nu se activase intreruperea pentru Timer0. In modul in care acum este setat prescaler-ul la TMR1 (adica este 1:1) viteza minima care se poate masura este de cca 920RPM. Pentru ca registrii pe 16bit pot numara pana la 65535. Cu raportul de 1:1 la prescaler ai practic 1us pe tick adica poate determina o durata maxima intre pulsuri de 65535us = 65.535ms. Convertim in frecventa si rezulta 1/65.535ms = 0.01525 rotatii/ms = 15.25rotatii/sec = 915RPM Daca folosesti un prescaler de 1:4 pt Timer1 atunci viteza minima care se poate masura este de 915RPM /4 deci vreo 230 RPM. S.a.m.d Dar in caz ca umbli la prescaler trebuie sa corectezi si cand faci conversia din durata in frecventa. Editat Octombrie 24, 2017 de mars01 Link spre comentariu
catalin004 Postat Octombrie 25, 2017 Autor Partajează Postat Octombrie 25, 2017 Ok...se pare ca acum merge....eu am ventilatorul de mai jos, la care ii citesc bpm-ul ca sa zic asa...momentan imi apar 7500 rpm pe display....dunctioneaza si LED-ul insa nu prea imi pare rotatia corecta...adica 5000 cred ca ar trebui sa arate...acum nu stiu, ati zic ca citeste doar 920 https://baraholka.onliner.by/viewtopic.php?t=18742259 Link spre comentariu
catalin004 Postat Octombrie 25, 2017 Autor Partajează Postat Octombrie 25, 2017 PS: In ce este mai avantajos sa programezi?in mikroC sau in MPlab....?adica ce este mai bine? Link spre comentariu
mars01 Postat Octombrie 25, 2017 Partajează Postat Octombrie 25, 2017 Ok...se pare ca acum merge....eu am ventilatorul de mai jos, la care ii citesc bpm-ul ca sa zic asa...momentan imi apar 7500 rpm pe display....dunctioneaza si LED-ul insa nu prea imi pare rotatia corecta...adica 5000 cred ca ar trebui sa arate...acum nu stiu, ati zic ca citeste doar 920 https://baraholka.onliner.by/viewtopic.php?t=18742259 Aici trebuie sa verifici cu osciloscopul ca sa ai pulsuri clare si bine definite. Este posibil sa ai si zgomot. Poti sa pui un mic filtru trece jos pe pinul uC-ului (CCP1). PS: In ce este mai avantajos sa programezi?in mikroC sau in MPlab....?adica ce este mai bine? La nivelul tau e bine sa ramai cu mikroC. Macar ai libraries-urile de functii oferite gata facute. In mplab cam trebuie sa le faci tu (sau te bazezi pe cele autogenerate de CCS dar sunt cam greu de inteles). Link spre comentariu
catalin004 Postat Octombrie 25, 2017 Autor Partajează Postat Octombrie 25, 2017 (editat) Am inteles....azi mai invatai cum sa fac headerre, cu sa le implementez in program...ca sa mai usurez munca...o sa vad ce fac si cu filtrul, poate chiar o sa-i pun un optocuplor, ideea era sa vad cum functioneaza...la mine nu imi sta in zero afisajul pentru ca rezistenta este legata la +5V, deci pinul de citire sta tot timpul in 1 logic, doar cand se invarte el pulseaza intre 0-5V... Am vazut ca exista si filtre soft, asa zicea colegul meu ca filtreaza o tensiune...etc...cred ca si o citire precisa se face tot cu timer nu? mai face si o mediere...ce-o mai fi si aia.... Editat Octombrie 25, 2017 de catalin004 Link spre comentariu
mars01 Postat Octombrie 25, 2017 Partajează Postat Octombrie 25, 2017 (editat) In acest caz ar trebui sa configurezi CCP1 ca sa numere pe "falling edge" si nu pe rising edge asa cum este setat acum, adica sa faci: CCP1CON = 0x04; sau altfel scris: CCP1CON = 0b00000100; // capture mode every falling edge Citeste si tu datasheet-ul ala ... Poti sa faci si o mediere daca vrei, este un fel de filtru trece jos software. Medierea aici este cand aduni sa zicem 10 sample-uri succesive si apoi suma o imparti la 10. Editat Octombrie 25, 2017 de mars01 Link spre comentariu
catalin004 Postat Octombrie 25, 2017 Autor Partajează Postat Octombrie 25, 2017 A...ok...oricum tot o sa-i pu opto...cred ca e mai ok....multumesc...gata acum trecem la alte jucarii....ma gandeam la un program care cu 2 butoane sa "chem " un anume procent al pwm-ului, adica sa apas pe increment pe display din 10 in 10% si motorul sa isi schimbe turatia, apoi invers....dar..de maine Link spre comentariu
catalin004 Postat Octombrie 26, 2017 Autor Partajează Postat Octombrie 26, 2017 (editat) Asa se face medierea?Am gasit intr-o postarea a dvs mai de mult....sau este mai complicat? Am inteles ca ar trebui eliminate capetele....adica prima si ultima citire....sau cate 2 din fiecare capete.... unsigned int i, rezultat; rezultat = ADC_read(); rezultat = 0; for (i = 0; i < 10; i++){ rezultat = rezultat + ADC_read(); } rezultat = rezultat / 10; Editat Octombrie 26, 2017 de catalin004 Link spre comentariu
Bandi Szasz Postat Octombrie 26, 2017 Partajează Postat Octombrie 26, 2017 (editat) /* Compiler = mikroC 7.1.0 uC type = 16F876A uC freq = 4MHz uC Datasheet = http://ww1.microchip.com/downloads/en/DeviceDoc/39582b.pdf Author = mars01, on elforum.ro */ sbit LCD_RS at RB4_bit; sbit LCD_EN at RB5_bit; sbit LCD_D4 at RB0_bit; sbit LCD_D5 at RB1_bit; sbit LCD_D6 at RB2_bit; sbit LCD_D7 at RB3_bit; sbit LCD_RS_Direction at TRISB4_bit; sbit LCD_EN_Direction at TRISB5_bit; sbit LCD_D4_Direction at TRISB0_bit; sbit LCD_D5_Direction at TRISB1_bit; sbit LCD_D6_Direction at TRISB2_bit; sbit LCD_D7_Direction at TRISB3_bit; unsigned int period_avg = 0; volatile unsigned int period = 0; volatile unsigned char reading_count = 0; volatile unsigned char display_flag = 0; unsigned char text[6]; // enough space for 5 characters // those are declared as volatile otherwise are optimized out by the compiler volatile unsigned int start = 0; volatile unsigned int stop = 0; // function prototype - declaration unsigned int period_func (unsigned int, unsigned int); void hw_init(); // function definition unsigned int period_func (unsigned int start_value, unsigned int stop_value){ return (stop_value - start_value); } void Interrupt(){ static unsigned int cnt = 0; static unsigned char flag = 0; if (CCP1IF_bit && CCP1IE_bit){ CCP1IF_bit = 0; // Reset CCP1 Interrupt period if (flag){ stop = (((unsigned int)CCPR1H)<< 8) | ((unsigned int)(CCPR1L)); // actual function usage (call) period += period_func(start, stop); reading_count++; flag = 0; // Reset Timer1 TMR1L = 0x00; TMR1H = 0x00; } else{ flag = 1; start = (((unsigned int)CCPR1H)<< 8) | ((unsigned int)(CCPR1L)); } } if (TMR0IF_bit && TMR0IE_bit){ // reset Timer0 TMR0IF_bit = 0; TMR0 = 0x06; // frequency will be displayed once every 500ms - twice per second if (cnt >= 500){ display_flag = 1; cnt = 0; } else{ cnt++; } } } // definitation of the hw_init() function which manage the HW initialization void hw_init(){ // Blink a LED to serve as a heart beat CMCON = 0x07; // comparators are OFF TRISA0_bit = 0; // RA0 is output; ADCON1 = 0xFF; // all pins are DIGITAL RA0_bit = 0; // RA0 start as OFF; // Configure CCP1 CCP1CON = 0b00000101; // capture mode every rising edge CCP1IF_bit = 0; // CCP1 interrupt flag - needs to be cleared in sw // Configure Timer1 T1CKPS1_bit = 0; // Timer1 prescaler set to 1:1; increment each 1us T1CKPS0_bit = 0; T1OSCEN_bit = 0; // LP oscillator is OFF TMR1CS_bit = 0; // TMR1 is incremented on internal clock TMR1ON_bit = 1; // enable Timer1 // Configure Timer0: Prescaler 1:4 and TMR0 preload with 0x06 PS2_bit = 0; // Prescaler configured at 1:4 PS1_bit = 0; PS0_bit = 1; NOT_RBPU_bit = 1; // pull-ups on Port B are disabled T0CS_bit = 0; // use internal instruction cycle clock PSA_bit = 0; // prescaler assigned to Timer0 TMR0 = 0x06; // preload the TMR0 register, combined with the prescaler value will give a 1ms interrupt // Initialize working registers TMR1L = 0x00; // Set Timer1 register to zero TMR1H = 0x00; CCPR1L = 0x00; // Initialize CCP register to 0 CCPR1H = 0x00; CCP1IE_bit = 1; // enable CCP1 interrupt TMR1IE_bit = 0; // disable TMR1 interrupt TMR0IE_bit = 1; // enable TMR0 interrupt // General enable of the interrupts GIE_bit = 1; // enable all interrupts PEIE_bit = 1; // enable peripheral interrupts LCD_init(); // initialize LCD Lcd_Cmd(_LCD_CLEAR); // Clear display Lcd_Cmd(_LCD_CURSOR_OFF); // Cursor off } void main(){ volatile unsigned long temp = 0; // volatile because otherwise it gets optimized out by the compiler // actual usage of our function that manage the hardware initialization hw_init(); Lcd_Out(1,1,"Frecventa: "); // display some static text, it will not change, on line 1 of the LCD while (1){ if (reading_count >= 10) { period_avg = period / reading_count; period = 0; reading_count = 0; } if (display_flag){ // if the time to display values has come (500ms passed) display_flag = 0; // make sure that you clear the flag so it is HIGH only when decided in the interrupt // LED heart beat RA0_bit = !RA0_bit; temp = 1000000 / period_avg; // convert period (measured in microseconds) in frequency temp = temp * 60; // we get RPM value (rotation per minute) out of the frequency (rotations per second) WordToStr(temp, text); // convert RPM value to text string Lcd_Out(2,1, text); // display the text on LCD on line 2 } } } Cam asa se face media pt variabila period. Treaba cu prima citire e valabila doar pentru citiri ADC (citirea unui tensiuni analogice), prima citire este ignorata si este folosita pt stabilizarea modulului de citire ADC, ultima citire nu imi dau seama de ce ar trebuii ignorata cel putin in cazul unui citiri ADC. Editat Octombrie 26, 2017 de Bandi Szasz 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