Sari la conținut
ELFORUM - Forumul electronistilor

Timer_16F877A_mikroC_Utilizare EEPROM


Vizitator

Postări Recomandate

Salutare,

Am acest proiect de pe net si vreau sa-l modific nitel.

Mai intai vreau sa va uitati un pic la fisiereul original si apoi la modificarea facuta de mine.

Cel original:

- setarea acestuia ramane memorata in EEPROM intern:

 ceasul functioneaza si la o cadere de tensiune, ceasul reporneste de la setarea facuta ultima oara si nu de la ora la care era in momentul in care sa luat tensiunea.

Modificarea facuta de mine:

- nu mai avem butoane pt setari, secunde, minute, ore si data (data a fost scoasa din proiect);

- am introdus la ore si sute de ore;

- am pus doua butoane: - pt functionarea ceasului doar cand este apasat;

                                       - pt resetarea ceasului.

- am refacut si utilizara meoriei EEPROM, ca atunci cand se intrerupe tensiunea, timer-ul nostru sa reporneasca de unde a ramas.

In concluzie, poate vati dat seama este un numarator de timp de functionare a unui bec, motor (va las pe voi sa va faceti idei)...

Daca este cineva doritor de acest proiect si vrea sa-l imbunatatim, eu m-am gandit sa-i atasam inca un buton care va seta de la 1 la 999 (ore) si cand timer-ul nostru este egal cu ora setata, pe iesirea unei porti prestabilita de noi sa actioneze un releu care va cupla un alt bec, motor,...

 

Dar mai intai sa rezolvam o problema pe care o am cu acest proiect, si anume:

Memoria interna EEPROM:

Functionarea este bunicica si de ce spun bunicica, deoarece daca se intrerupe tensiunea de doua ori sau mai mult la revenirea tensiunii pe afisaj unele cifre sunt inlocuite cu cifra 5 sau litera I mare. Probabil nu am facut cum trebuie programul si vreau sa trageti cu ochiul ( nu pe vizorul de la usa auzind tocurile vecinei,...  :limb:  ), la proiectul meu.

Proiectul modificat de mine este acesta:  

(iar cel original este in Arhiva impreuna cu fisireul in PROTEUS pt proiectul modificat)

 

// LCD module connections
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;
// End LCD module connections
 
char sec, zsec, m, zm, h, zh, sh;
char *text = "000:00:00";
unsigned cnt;
 
void interrupt()
{
 
TMR0=5;
cnt++;
INTCON.TMR0IF=0;
if (PORTC.F0==1){
if(cnt>=2){     // cnt>=1000 = 1Hz
 cnt = 0;
 sec++;
 if(sec>=10)
 {
 sec=0;
 zsec++;
 if(zsec>=6)
 {
 sec=0;
 zsec=0;
 m++;
 if(m>=10)
 {
 //sec=0;
 m=0;
 zm++;
 if(zm>=6)
 {
 sec=0;
 m=0;
 zm=0;
 h++;
 if(h>=10)
 {
 h=0;
 zh++;
 if(zh>=10)
 {
 sec=0;
 m=0;
 zm=0;
 h=0;
 zh=0;
 sh++;
 if(sh>=10)
 {
 sec=0;
 zm=0;
 h=0;
 zh=0;
 sh=0;
 }
 }
 }
 }
 }
 }
 }
}
}
}
 
void main()
{
CMCON |= 0x07;
ADCON1 = 0x00;
 
TRISB = 0xFF;
TRISC = 0xFF;
 
INTCON.GIE = 1;
INTCON.PEIE = 1;
INTCON.TMR0IE = 1;
OPTION_REG = 0b10000010;
TMR0 = 5;
sec  = Eeprom_Read(0x00);
zsec = Eeprom_Read(0x01);
m    = Eeprom_Read(0x02);
zm   = Eeprom_read(0x03);
h    = Eeprom_Read(0x04);
zh   = Eeprom_Read(0x05);
sh   = Eeprom_Read(0x06);
 
 
Lcd_Init();
Lcd_Cmd(_LCD_CLEAR);
Lcd_Cmd(_LCD_CURSOR_OFF);
 
do
{
 
 
text[8] = sec%10 + '0';
Eeprom_Write(0x00, sec);
text[7] = zsec%10 + '0';
Eeprom_Write(0x01, zsec);
text[5] = m%10 + '0';
Eeprom_Write(0x02, m);
text[4] = zm%10 + '0';
Eeprom_Write(0x03, zm);
text[2] = h%10 + '0';
Eeprom_Write(0x04, h);
text[1] = zh%10 + '0';
Eeprom_Write(0x05, zh);
text[0] = sh%10 + '0';
Eeprom_Write(0x06, sh);
 
Lcd_Out(1, 4, text);
 
if (PORTC.F1==1)
{
sec=0;
zsec=0;
m=0;
zm=0;
h=0;
zh=0;
sh=0;
}
 
}while(1);
}

 

Link spre comentariu
  • Răspunsuri 16
  • Creat
  • Ultimul Răspuns

Top autori în acest subiect

Top autori în acest subiect

UDAR, cred ca esti multumit de rezultatul de la tenis.

 

Da cum ramane cu EEPROM-ul scris cam des?

La inceput scrierea in EEPROM era cam asa:

text[6] = sec/10 + '0';
text[7] = sec%10 + '0';
Eeprom_Write(0x00,sec); // SECUNDE
text[3] = m/10 + '0';
text[4] = m%10 + '0';
Eeprom_Write(0x01,m); // MINUTE
text[0] = h/10 + '0';
text[1] = h%10 + '0';
Eeprom_Write(0x02,h); // ORE
text[0] = sh% + '0';  // Adaugat de mine Sute de ore
Eeprom_Write(0x03,sh);

Am vazut ca am acesta problema, de afisare a cifrei 5 dupa ce revine tensiunea, am refacut inscrierea memoriei EEPROM:

text[8] = sec%10 + '0';
Eeprom_Write(0x00, sec); // secunde
text[7] = zsec%10 + '0';
Eeprom_Write(0x01, zsec); // zeci de secunde
text[5] = m%10 + '0';
Eeprom_Write(0x02, m); // minute
text[4] = zm%10 + '0';
Eeprom_Write(0x03, zm); // zeci de minute
text[2] = h%10 + '0';
Eeprom_Write(0x04, h); // ore
text[1] = zh%10 + '0';
Eeprom_Write(0x05, zh); // zeci de ore
text[0] = sh%10 + '0';
Eeprom_Write(0x06, sh); // sute de ore
 
Aseara am pornit cronometrul si l-am oprit la o valoare oarecare pe care mi-am notat-o intr-un carnetel, dar sa nu cuprinda cifra 5 nicaieri.
Dimineata, am repornit cronometrul si, surpriza cronometrul afisa acea-si valoare scrisa in carnetel cu o seara in urma.
dupa doua minute am inchis cronometrul si l-am redeschis dupa 5 minute. Surpriza, una dintre cifre a fost inlocuita cu cifra 5.

De ce nu am stabilitate la memoria EEPROM?

Mentionez ca nu am pus condensator de filtrare intre portc.f0, portc.f1 si Vcc in paralel cu butoanele poate fi aceasta o cauza?

Editat de Vizitator
Link spre comentariu

De obicei la butoane se face verificare dubla. Daca ai 1 pe buton faci un mic delay si verifici din nou, daca a fost un "parazit" atunci dupa acel mic delay sunt putine sanse sa mai fie prezent si astfel se elimina impulsurile false. 

 

Sau mai simplu in MikroC exista functia Button() care se ocupa de verificare dubla.

 

In legatura cu EEPROM nu stiu ce sa zic, de obicei este utilizat pentru a stoca settari dinamice. Nu stiu cat o sa reziste sa fie scris la fiecare secunda. Microchip garanteaza 100,000 de scrieri/stergeri poate rezista si mult mai mult dar ei atata garanteaza, daca tu il scrii in fiecare secunda ramane de vazut cat tine. 

 

In cazul de fata ar trebuii implementat un fell de backup pe baterie, cand pica alimentarea PIC-ul trece in sleep alimentat de la o baterie( o sa fie consum sub 1mA) cand revine alimentarea iese din sleep si isi continua treaba. 

if (PORTC.F1==1){ delay_ms(50);  if (PORTC.F1==1)  {    ......  }}
Editat de bandi12
Link spre comentariu

”In legatura cu EEPROM nu stiu ce sa zic, de obicei este utilizat pentru a stoca settari dinamice. Nu stiu cat o sa reziste sa fie scris la fiecare secunda. Microchip garanteaza 100,000 de scrieri/stergeri poate rezista si mult mai mult dar ei atata garanteaza, daca tu il scrii in fiecare secunda ramane de vazut cat tine. ”

 

Mulțumesc @bandi12 pentru răspuns în locul meu . Exact la anduranța limitată a EEPROM-ului mă refeream .

Link spre comentariu

Cam asta am gasit in documentatia lui PIC16F87XA:

Special Microcontroller Features:

100,000 erase/write cycle Enhanced Flash program memory typical

1,000,000 erase/write cycle Data EEPROM memory typical

• Data EEPROM Retention > 40 years

 

Iar o memorie EEPROM I2C cum ar fi 24C03

• 1,000,000 Program/Erase Cycles

Dupa cum se observa memoriile EEPROM au acelasi nr de programare/stergere fie ele interne sau externe.

 

Cred ca o sa ma gandesc la o schema cu baterie de backup pt microcontroller, ca sincer am vazut in multe automatizari pt a nu forta rescrierea memoriei EEPROM, mai ales la o secunda cum este cazul meu.

Link spre comentariu

1.000.000 e tipic , 100.000 e garantat . Paragraful 17.2 din DS , parametrul D120. Pagina 179 dacă citești aceeași ediție.

Dar , fie 1.000.000 . O dată pe secundă înseamnă mai puțin de 12 zile . În fine , era doar o constatare .

Editat de UDAR
Link spre comentariu

O constatare buna UDAR si va multumesc, am calculat si eu si a iesit aproximativ 12 zile.

Voi elimina memoria EEPROM din proiect si voi continua cu acesta, dar cu baterie backup.

Acuma voi adauga la proiect un buton de setare a timpului de functionare a becului (, motorului) si inversarea acestuia cu un altul si tot asa.

 

Exemplu:

100:00:00 = 100 (setat) un releu va comuta pe becul (motorul) de rezerva.

Editat de Vizitator
Link spre comentariu

Da UDAR, si asta este o ideie... deja ma gandesc la asa ceva, restul proiectului mai tarziu   :)

Si stii dece, pt ca este pacat sa nu memorez in EEPROM. Si oare de cate ori se va lua tensiunea, de 20 de ori pe an?

 

Am refacut proiectul:

 

...

do
{
text[8] = sec%10 + '0';
text[7] = zsec%10 + '0';
text[5] = m%10 + '0';
text[4] = zm%10 + '0';
text[2] = h%10 + '0';
text[1] = zh%10 + '0';
text[0] = sh%10 + '0';
 
 
Lcd_Out(1, 4, text);
 
if (PORTC.F2==1)
{
Eeprom_Write(0x00, sec);
Eeprom_Write(0x01, zsec);
Eeprom_Write(0x02, m);
Eeprom_Write(0x03, zm);
Eeprom_Write(0x04, h);
Eeprom_Write(0x05, zh);
Eeprom_Write(0x06, sh);
}
 
if (PORTC.F1==1)
{
sec=0;
zsec=0;
m=0;
zm=0;
h=0;
zh=0;
sh=0;
}
 
}while(1);
}
 
si merge perfect acuma. Nu mai am afisata cifra 5 dupa cum vrea microcontrollerul. Da cei dupa el, nui asa UDAR si bandi12
 
Si aceasta schema, cred ca ma poate ajuta, nu?
Editat de Vizitator
Link spre comentariu

De D2 nu ai nevoie iar R6 il maresti cat poti de mult (dar nu prea mult daca vrei sa ai un nivel HIGH ferm cand Q1 este activ, as zice ca 47K este OK) pentru ca o sa iti consume din condensator mai mult decat controller-ul.

 

LE: si o recomandare. Daca tot schimbi firmware-ul atunci foloseste un alt controller, de generatie mai noua (si mai ieftin), care sa aiba oscilator intern (low power) si sa ii poti schimba clock-ul cu registrul OSCCON. Ceva cu 28 pini ar trebui sa fie suficient.

Cand controller-ul detecteaza evenimentul de POWER_DOWN atunci scazi si frecventa clock-ului pentru a minimiza consumul. Sau o alta chestie ar fi (nu stiu daca merge eu nu am facut-o pana acum) sa pui controller-ul in SLEEP cand scrie in EEPROM.

Editat de mars01
Link spre comentariu

daca vrei sa faci ceva profesional faci asa:

 

HARD

alimentezi montajul la 12v

ptr partea logica (PIC) folosesti un convertor "step-down" MC34063

faci un divizor rezistiv sa scoata o tensiune de ~2v la 9v tensiunea de pe intrare(12v)

iesirea divizorului o bagi in PIC la intrarea comparatorului

 

acum SOFT

setezi comparatorul la ~2v sa dea o intrerupere cind se schimba starea iesiri

cind esti in intrerupere

 verifici iesirea comparatorului

  daca a cazut tensiunea

salvezi datele in EEPROM,

activezi interuperile si apoi SLEEP

  daca a revenit tensiunea RESET

 

cind salvezi datele trebuie sa faci foarte repede

sper ca am explicat bine

Link spre comentariu

Am refacut un pic partea de alimentare a microcontrollerului la recomandarea lui UDAR si am modificat programul  tinand cont de sfatul lui sofian, folosind un comparator.

 

unsigned long temp;

...

Lcd_Out(1, 4, text);
 
    temp = ADC_Read(0);   // Get 10-bit results of AD conversion
    temp=temp*5000/1023;   //Convert ADC value to mV
 
    if (temp>=4200) { PORTC.F2=0; }
    if (temp<=4000) { PORTC.F2=1; }
    if (temp<=3500) { PORTC.F2=0; }

 

Am folosit aceeasi sursa de 5 volti, am pus un LED pe pinul 17 portC.f2 sa urmaresc starea acestuia.

Am testat live si functioneaza perfect acuma.

 

NU am inteles partea cu :

     activezi interuperile si apoi SLEEP ???

  daca a revenit tensiunea RESET ??? 

Editat de Vizitator
Link spre comentariu

SLEEP este o functionalitate a PIC-ului care permite oprirea aproape totala a PIC-ului dar fara a pierde datele. Variabilele isi pastreaza valoarea dar se suspenda rularea programului, oscilatorul este oprit impreuna cu mai multe module interne. PIC-ul in functionare consuma cam 4-10mA ( depinde de module interne activate etc... ) , in mod SLEEP consumul scade drastic la cateva nA. Cum PIC-ul este oprit total nu putem sa-l trezim din program de acea avem in majoritatea cazurilor 2 optini :

 

 - impuls (intrerupere)  externa de care vorbea Sofian. Care poate fii revenirea alimentarii, pe pin -ul de intrerupere apare un voltaj = pic-ul il vede ca impuls =>> se trezeste.

 - modulul watchdog care este un modul separat "stand-alone" care poate fii activat si functioneaza separat. Acest modul in sine este un timer care poate da impulsul necesar pentru trezire. Problema este ca are o limita maxima de timp, deci se foloseste cu sleep-uri multiple. Se pune PIC-ul in SLEEP watchdog-ul il trezeste in cateva secunde, se verifica daca criteriul de SLEEP este inca valid ( adica lipsa alimentare) daca da se pune din nou in SLEEP. Aceasta metoda necesita iesirea din SLEEP destul de frecvent de acea este de preferat un impuls extern.

 

Nu sunt prea sigur de intentia lui Sofian tinand cont ca schema este cu condensator nu prea are rost functia SLEEP daca PIC-ul are destul timp sa salveze in EEPROM. Eu am recomandat functia de sleep in cazul unui backup pe baterie care ar fii prelungit dramatic durata de viata a bateriei, dar daca ai ales varianta cu condensator si salvarea in EEPROM cel putin eu nu vad rostul lui SLEEP care ar tine PIC-ul in "viata" pe condensator inca cateva secunde.

 

Poate o sa ne lamureasca Sofian.

Editat de bandi12
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