Liviu M Postat Octombrie 1, 2015 Partajează Postat Octombrie 1, 2015 (editat) Manualul de la xc8 e destul de detaliat referitor la volatile: 5.4.7.2 VOLATILE TYPE QUALIFIERThe volatile type qualifier is used to tell the compiler that an object cannot be guaranteed to retain its value between successive accesses. This prevents the optimizer from eliminating apparently redundant references to objects declared volatile because it can alter the behavior of the program to do so.Any SFR which can be modified by hardware or which drives hardware is qualified as volatile, and any variables which can be modified by interrupt routines should use this qualifier as well. For example: volatile static unsigned int TACTL @ 0x160; The volatile qualifier does not guarantee that any access will be atomic, which is often not the case with the 8-bit PIC MCU architecture. All these devices can only access a maximum of 1 byte of data per instruction. The code produced by the compiler to access volatile objects can be different to that to access ordinary variables, and typically the code will be longer and slower for volatile objects, so only use this qualifier if it is necessary. However, failure to use this qualifier when it is required can lead to code failure.Another use of the volatile keyword is to prevent variables being removed if they are not used in the C source. If a non-volatile variable is never used, or used in a way that has no effect on the program’s function, then it can be removed before code is generated by the compiler.A C statement that consists only of a volatile variable’s name will produce code that reads the variable’s memory location and discards the result. For example the entire statement: PORTB; will produce assembly code the reads PORTB, but does nothing with this value. This is useful for some peripheral registers that require reading to reset the state of interrupt flags. Normally such a statement is not encoded as it has no effect.Some variables are treated as being volatile even though they cannot be qualified in the source code. See Section 5.12.3.4 “Undefined Symbols” if you have assembly code in your project. Editat Octombrie 1, 2015 de Liviu M 1 Link spre comentariu
mars01 Postat Octombrie 1, 2015 Partajează Postat Octombrie 1, 2015 (editat) Multumesc Liviu pentru completare. Si eu gasesc ca manualul pt XC8 este foarte instructiv si mai arunc cate o privire din cand in cand. Poate nu atat de des cat ar trebui... Si altfel spus, mai concis, sursa este aici: "What could cause corrupted variables or code failure when I am using interrupts? FAQs » What could cause corrupted variables or code failure when I am using interrupts? Posted on Thursday: 17 April 2014 Variables accessed from both interrupt and main-line code can easily become corrupted or misread by the program. Such variables should be qualified as "volatile". This will prevent the compiler from using cached copies of the variable in main line code from the Interrupt Service Routine code and vice versa. Volatile qualified variables will also not be optimized away. The compiler will also attempt to access the variable atomically, but this is not always possible if the assembly instruction set does not permit this. You can check the assembly list file to see the assembly code used to access variables and determine if the access is atomic. If it is not, consider disabling the interrupts when it is accessed in main-line code." Editat Octombrie 1, 2015 de mars01 Link spre comentariu
Myhayxx Postat Octombrie 1, 2015 Partajează Postat Octombrie 1, 2015 Am facut eu o prima versiune, am atasat simularea in proteus cat si codul sursa in mikroC. L-a pornire intra meniul de setare a intervalului ON ( OFF se calculeaza automat din moment ce ON+OFF = 1 ora) cu butonul 2 se incrementeaza minutele cu butonul 3 se incrementeaza secundele (pentru "pedalare" la valori mari de ex. 50s se tine butonul apasat")dupa ce setarea este facuta se apasa butonul 1 se afiseaza un mesaj de confirmare si incepe ciclul cu intervalul ON. Daca se doreste modificarea intervalului in timpul functionarii se apasa butonul 1 si se seteaza din nou ca la pornire. poti sa-mi zici te rog ce trebuie modificat in program ca sa nu se mai reia ciclul de temporizare? Link spre comentariu
Bandi Szasz Postat Octombrie 1, 2015 Partajează Postat Octombrie 1, 2015 (editat) poti sa-mi zici te rog ce trebuie modificat in program ca sa nu se mai reia ciclul de temporizare? Am facut modificarile si am lasat si partea cu ciclu repetitiv in comentariu + am facut modificarea recomandata la msTime in volatile Modificarile au fost facute in setTime() si checkTimer() Cod: sbit LCD_RS at RA0_bit;sbit LCD_EN at RA1_bit;sbit LCD_D7 at RB7_bit;sbit LCD_D6 at RB6_bit;sbit LCD_D5 at RB5_bit;sbit LCD_D4 at RB4_bit;// Pin directionsbit LCD_RS_Direction at TRISA0_bit;sbit LCD_EN_Direction at TRISA1_bit;sbit LCD_D7_Direction at TRISB7_bit;sbit LCD_D6_Direction at TRISB6_bit;sbit LCD_D5_Direction at TRISB5_bit;sbit LCD_D4_Direction at TRISB4_bit;#define relay PORTB.F3volatile int msTime;//char relay=1;int onTime = 6 ; // in secundeint TimeLeft = 6; // in secundechar *timeToLCD="00m00s";void Init_LCD() { Lcd_Init(); Lcd_Cmd(_LCD_CURSOR_OFF); Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,6, "Hello!"); delay_ms(1000); Lcd_Cmd(_LCD_CLEAR);}void InitTimer1(){ T1CON = 0x31; TMR1IF_bit = 0; TMR1H = 0x0B; TMR1L = 0xDC; TMR1IE_bit = 1; INTCON = 0xC0;}void Interrupt(){ if (TMR1IF_bit){ TMR1IF_bit = 0; TMR1H = 0x0B; TMR1L = 0xDC; msTime++; }}void DisplayData() { int TlSecounds,TlMinutes; TlMinutes = TimeLeft/60; TlSecounds = TimeLeft-TlMinutes*60; Lcd_Out(1,1, "Relay is: "); if(relay) Lcd_Out(1,11, "ON "); else Lcd_Out(1,11, "OFF "); Lcd_Out(2,1,"TimeLeft:"); timeToLCD[4] = TlSecounds%10+48; timeToLCD[3] = TlSecounds/10%10+48; timeToLCD[1] = TlMinutes%10+48; timeToLCD[0] = TlMinutes/10%10+48; Lcd_Out(2,10,timeToLCD);}void DisplaySetupData() { int TlSecounds,TlMinutes; TlMinutes = onTime/60; TlSecounds = onTime-TlMinutes*60; Lcd_Out(2,1,"On Time:"); timeToLCD[4] = TlSecounds%10+48; timeToLCD[3] = TlSecounds/10%10+48; timeToLCD[1] = TlMinutes%10+48; timeToLCD[0] = TlMinutes/10%10+48; Lcd_Out(2,10,timeToLCD);}void CheckTime() { if(msTime >= 10) { TimeLeft--; msTime=0; /* if(TimeLeft == 0) ciclu repetitiv { if(relay) TimeLeft = 3600-OnTime; else TimeLeft = onTime; relay=!relay; } */ if(TimeLeft == 0) // un singur ciclu { T1CON.F0 = 0; relay = 0; } }}void SetTime() { onTime = 0; Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,5,"Set Time"); delay_ms(500); while(Button(&PORTB,0,10,0) == 0) { DisplaySetupData(); if(Button(&PORTB,1,10,0)) { onTime+=60; delay_ms(250); } if(Button(&PORTB,2,10,0)) { onTime+=1; delay_ms(250); } } Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,2,"Time Setup Done!"); delay_ms(1000); TimeLeft = onTime; relay = 1; T1CON.F0 = 1; Lcd_Cmd(_LCD_CLEAR);}void main() { CMCON |= 7; TRISB = 0x7; OPTION_REG.F7 = 0; Init_LCD(); InitTimer1(); //100ms setTime(); while(1) { if(Button(&PORTB,0,10,0)) SetTime(); checkTime(); DisplayData(); delay_ms(25); }} Editat Octombrie 1, 2015 de bandi12 Link spre comentariu
Myhayxx Postat Octombrie 1, 2015 Partajează Postat Octombrie 1, 2015 iti multumesc mult de tot. am simulat si merge perfect. maine ma apuc de realizat timerul Link spre comentariu
Myhayxx Postat Octombrie 3, 2015 Partajează Postat Octombrie 3, 2015 (editat) cam asa arata timerul construit de mine cu ajutorul colegului "bandi12".Multumesc! insa am o problema: atunci cand apesi butonul ON/OFF se activeaza releul si asa ramane si dupa ce iau alimentarea montajului. as vrea daca se poate modifica in program sa nu mai existe functia de ON/OFF. Editat Octombrie 3, 2015 de Myhayxx Link spre comentariu
quinn Postat Octombrie 3, 2015 Autor Partajează Postat Octombrie 3, 2015 a pornit si la mine de 10 min. dar cu softul initial,nu am trecut la modificarea cu msTime ,e vreo problema? Link spre comentariu
Bandi Szasz Postat Octombrie 3, 2015 Partajează Postat Octombrie 3, 2015 @Myhayxx Din cate am inteles eu : Sa adaugat un buton On/Off care intrerupe alimentarea montajului, in momentul in care montajul se alimenteaza cupleaza releu si daca se intrerupe alimentarea montajului din butonul On/Off releul ramane cuplat ? @quinn: Nu este o problema, eu pana acuma nu am folosit abnotatia "volatile" si nu am avut probleme pana acuma. In cel mai extrem caz se pierd cateva millisecunde din timpul setat dar nu cred ca e cazul. Link spre comentariu
Myhayxx Postat Octombrie 3, 2015 Partajează Postat Octombrie 3, 2015 (editat) al patrulea buton care l-am pus este cel de reset. Problema se manifesta in felul urmator: daca tii apasat pe butonul ON/OFF releul isi schimba pozitia (initial fiind neatras) din decuplat in cuplat (ramanand atras tot timpul) chiar daca apas pe butonul de RESET sau ii iau alimentarea montajului(in timpul cand nu este alimentat releul nu mai e atras;dar la revenire cu tensiune se atrage din nou).tot in acest timp pot modifica valoarea de la minute si secunde dar in momentul cand ii dau start nu se intampla nimic(contorul se blocheaza) de aceea vroiam sa dezactivez aceasta functie. Mie imi trebuie ca la alimentarea montajului releul sa nu fie atras,setez timpul,pornesc cronometrul se atrage releul si dupa scurgerea timpului setat sa se opreasca. Editat Octombrie 3, 2015 de Myhayxx Link spre comentariu
Bandi Szasz Postat Octombrie 3, 2015 Partajează Postat Octombrie 3, 2015 (editat) Am inteles. Deci butonul on/off ar fi cel numit "menu" in simularea pe care l-am atasat. O "eroare" descoperita in simulare ar fi pornirea cronometrului cu 00m00s ( nechimbat valoarea se apasa butonul start) in acel moment se blocheaza programul, probabil de aicea se trage problema. Fac corectarea pe codul meu sau postati / imi trimiteti pe privat codul sa nu mai trebuiasca sa modificati din nou textul de afisare ? Editat Octombrie 3, 2015 de bandi12 Link spre comentariu
Myhayxx Postat Octombrie 4, 2015 Partajează Postat Octombrie 4, 2015 faceti corectarea pe codul dumneavoastra poate mai are cineva nevoie de aceasta versiune, nu-i mare lucru sa schimb un text, macar atat sa fac si eu . Am incercat sa fac modificarile in program dar nu mi-a iesit, mai am ult de invatat . va multumesc pentru ajutor! Link spre comentariu
quinn Postat Octombrie 4, 2015 Autor Partajează Postat Octombrie 4, 2015 (editat) am observat si eu ca uneori la alimentare,este iesirea activa,alteori nu Editat Octombrie 4, 2015 de quinn Link spre comentariu
Myhayxx Postat Octombrie 4, 2015 Partajează Postat Octombrie 4, 2015 tot facand teste am mai intalnit si urmatoarea problema: la prima alimentare a timerului dupa ce a stat ceva timp nealimentat setez timpul iar cand ii dau start nu mai pleaca timerul, ramane blocat si isi revine greu dupa ce ii dau cateva reset-uri iar apoi merge fara probleme. S-ar putea sa fie din cauza ca am folosit PIC16F628 si nu PIC16F628A. Care este diferenta intre cele doua modele? Link spre comentariu
Bandi Szasz Postat Octombrie 4, 2015 Partajează Postat Octombrie 4, 2015 (editat) Pentru un singur ciclu sbit LCD_RS at RA0_bit;sbit LCD_EN at RA1_bit;sbit LCD_D7 at RB7_bit;sbit LCD_D6 at RB6_bit;sbit LCD_D5 at RB5_bit;sbit LCD_D4 at RB4_bit;// Pin directionsbit LCD_RS_Direction at TRISA0_bit;sbit LCD_EN_Direction at TRISA1_bit;sbit LCD_D7_Direction at TRISB7_bit;sbit LCD_D6_Direction at TRISB6_bit;sbit LCD_D5_Direction at TRISB5_bit;sbit LCD_D4_Direction at TRISB4_bit;#define relay PORTB.F3volatile int msTime;//char relay=1;int onTime = 6 ; // in secundeint TimeLeft = 6; // in secundechar *timeToLCD="00m00s";void Init_LCD() { Lcd_Init(); Lcd_Cmd(_LCD_CURSOR_OFF); Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,6, "Hello!"); delay_ms(1000); Lcd_Cmd(_LCD_CLEAR);}void InitTimer1(){ T1CON = 0x31; TMR1IF_bit = 0; TMR1H = 0x0B; TMR1L = 0xDC; TMR1IE_bit = 1; INTCON = 0xC0;}void Interrupt(){ if (TMR1IF_bit){ TMR1IF_bit = 0; TMR1H = 0x0B; TMR1L = 0xDC; msTime++; }}void DisplayData() { int TlSecounds,TlMinutes; TlMinutes = TimeLeft/60; TlSecounds = TimeLeft-TlMinutes*60; Lcd_Out(1,1, "Relay is: "); if(relay) Lcd_Out(1,11, "ON "); else Lcd_Out(1,11, "OFF "); Lcd_Out(2,1,"TimeLeft:"); timeToLCD[4] = TlSecounds%10+48; timeToLCD[3] = TlSecounds/10%10+48; timeToLCD[1] = TlMinutes%10+48; timeToLCD[0] = TlMinutes/10%10+48; Lcd_Out(2,10,timeToLCD);}void DisplaySetupData() { int TlSecounds,TlMinutes; TlMinutes = onTime/60; TlSecounds = onTime-TlMinutes*60; Lcd_Out(2,1,"On Time:"); timeToLCD[4] = TlSecounds%10+48; timeToLCD[3] = TlSecounds/10%10+48; timeToLCD[1] = TlMinutes%10+48; timeToLCD[0] = TlMinutes/10%10+48; Lcd_Out(2,10,timeToLCD);}void CheckTime() { if(msTime >= 10) { TimeLeft--; msTime=0; /* if(TimeLeft == 0) ciclu repetitiv { if(relay) TimeLeft = 3600-OnTime; else TimeLeft = onTime; relay=!relay; } */ if(TimeLeft == 0 && relay == 1) // un singur ciclu { T1CON.F0 = 0; relay = 0; } }}void SetTime() { onTime = 0; Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,5,"Set Time"); delay_ms(500); while(Button(&PORTB,0,10,0) == 0) { DisplaySetupData(); if(Button(&PORTB,1,10,0)) { onTime+=60; delay_ms(250); } if(Button(&PORTB,2,10,0)) { onTime+=1; delay_ms(250); } } Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,2,"Time Setup Done!"); delay_ms(1000); TimeLeft = onTime; if(TimeLeft == 0) { relay = 0; T1CON.F0 = 0; } else { relay = 1; T1CON.F0 = 1; } Lcd_Cmd(_LCD_CLEAR);}void main() { CMCON |= 7; TRISB = 0x7; relay = 0; OPTION_REG.F7 = 0; Init_LCD(); InitTimer1(); //100ms T1CON.F0 = 0; setTime(); while(1) { if(Button(&PORTB,0,10,0)) SetTime(); checkTime(); DisplayData(); delay_ms(25); }} Pentru ciclu repetitiv : sbit LCD_RS at RA0_bit;sbit LCD_EN at RA1_bit;sbit LCD_D7 at RB7_bit;sbit LCD_D6 at RB6_bit;sbit LCD_D5 at RB5_bit;sbit LCD_D4 at RB4_bit;// Pin directionsbit LCD_RS_Direction at TRISA0_bit;sbit LCD_EN_Direction at TRISA1_bit;sbit LCD_D7_Direction at TRISB7_bit;sbit LCD_D6_Direction at TRISB6_bit;sbit LCD_D5_Direction at TRISB5_bit;sbit LCD_D4_Direction at TRISB4_bit;#define relay PORTB.F3volatile int msTime;//char relay=1;int onTime = 6 ; // in secundeint TimeLeft = 6; // in secundechar *timeToLCD="00m00s";void Init_LCD() { Lcd_Init(); Lcd_Cmd(_LCD_CURSOR_OFF); Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,6, "Hello!"); delay_ms(1000); Lcd_Cmd(_LCD_CLEAR);}void InitTimer1(){ T1CON = 0x31; TMR1IF_bit = 0; TMR1H = 0x0B; TMR1L = 0xDC; TMR1IE_bit = 1; INTCON = 0xC0;}void Interrupt(){ if (TMR1IF_bit){ TMR1IF_bit = 0; TMR1H = 0x0B; TMR1L = 0xDC; msTime++; }}void DisplayData() { int TlSecounds,TlMinutes; TlMinutes = TimeLeft/60; TlSecounds = TimeLeft-TlMinutes*60; Lcd_Out(1,1, "Relay is: "); if(relay) Lcd_Out(1,11, "ON "); else Lcd_Out(1,11, "OFF "); Lcd_Out(2,1,"TimeLeft:"); timeToLCD[4] = TlSecounds%10+48; timeToLCD[3] = TlSecounds/10%10+48; timeToLCD[1] = TlMinutes%10+48; timeToLCD[0] = TlMinutes/10%10+48; Lcd_Out(2,10,timeToLCD);}void DisplaySetupData() { int TlSecounds,TlMinutes; TlMinutes = onTime/60; TlSecounds = onTime-TlMinutes*60; Lcd_Out(2,1,"On Time:"); timeToLCD[4] = TlSecounds%10+48; timeToLCD[3] = TlSecounds/10%10+48; timeToLCD[1] = TlMinutes%10+48; timeToLCD[0] = TlMinutes/10%10+48; Lcd_Out(2,10,timeToLCD);}void CheckTime() { if(msTime >= 10) { TimeLeft--; msTime=0; if(TimeLeft == 0) // ciclu repetitiv { if(relay) TimeLeft = 3600-OnTime; else TimeLeft = onTime; relay=!relay; } /* if(TimeLeft == 0 && relay == 1) // un singur ciclu { T1CON.F0 = 0; relay = 0; } */ }}void SetTime() { onTime = 0; Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,5,"Set Time"); delay_ms(500); while(Button(&PORTB,0,10,0) == 0) { DisplaySetupData(); if(Button(&PORTB,1,10,0)) { onTime+=60; delay_ms(250); } if(Button(&PORTB,2,10,0)) { onTime+=1; delay_ms(250); } } Lcd_Cmd(_LCD_CLEAR); Lcd_Out(1,2,"Time Setup Done!"); delay_ms(1000); TimeLeft = onTime; if(TimeLeft == 0) { relay = 0; T1CON.F0 = 0; } else { relay = 1; T1CON.F0 = 1; } Lcd_Cmd(_LCD_CLEAR);}void main() { CMCON |= 7; TRISB = 0x7; relay = 0; OPTION_REG.F7 = 0; Init_LCD(); InitTimer1(); //100ms T1CON.F0 = 0; setTime(); while(1) { if(Button(&PORTB,0,10,0)) SetTime(); checkTime(); DisplayData(); delay_ms(25); }} Iesirea la alimentare este o greseala a mea, am uitat sa specific ca la pornire sa fie off si atunci PIC-ul la pornire nestind ce sa faca cu iesirea se produce o alegere aleatorie, de acolo a rezultat ca in momentul alimentarii cand e on cand e off. Nu ar trebuii sa faca figuri intre varianta normala si cea cu "A", eventual cand compilati codul in MikroC sa alegeti versiunea normala fara "A" si oscilatorul la 20Mhz. Editat Octombrie 4, 2015 de bandi12 Link spre comentariu
Myhayxx Postat Octombrie 4, 2015 Partajează Postat Octombrie 4, 2015 acum programul eset in regula ca functionalitate. A mai ramas doar problema cu prima alimentare. ori de cate ori ii iau alimentarea si revin cu ea dupa ce setez ceasul si ii dau start se blocheaza isi revine doar dupa cateva operatii de setare pornire, reset apoi dupa ce isi revine functioneaza fara probleme de cate ori programez. nu-mi dau seama unde ar fi problema.. o sa fac un filmulet sa vedeti despre ce este vorba. daca nu reusesc il folosesc asa, o sa il las alimentat non-stop. 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