Sunteți pe pagina 1din 33

Problema pagina 71- rezolvata

Intreruperea unui program DOS din executie se poate face utilizind CTRL+C sau CTRL+BREAK. Prin utilizarea comenzii BREAK in CONFIG.SYS sau ca o comanda obisnuita DOS, sistemul de operare poate fi determinat sa verifice actionarea tastelor respective in timpul oricarui apel sistem (BREAK=ON) sau sa faca verificarea numai in timpul apelurilor sistemului pentru operatiile de I/E cu echipamente periferice standard (BREAK=OFF). In program se foloseste astfel apelul sistem 09H pentru afisarea unui sir de caractere iar in timpul executiei acestui apel se face testul de actionare CTRL+BREAK. Programul de mai sus se poate scrie si in limbajul C/C++, PASCAL etc. fie prin utilizarea functiilor speciale pentru intreruperi, existente in bibliotecile mediilor de dezvoltare, fie prin utilizarea programarii mixte limbaj evoluat / limbaj de asamblare. O versiune a programului scrisa in Borland C/C++ este urmatoarea:
#include <stdio.h> #include <dos.h> #include <conio.h> #define INTR_8 0X08 /* Intreruperea de la ceas, la aprox. 55ms*/ #define INTR_23 0X23 /* Intreruperea CTRL_BREAK */ #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif unsigned char oldmask_1=0; void interrupt ( *oldint8)(__CPPARGS); void interrupt ( *oldint23)(__CPPARGS); int count=0,oldcount=0,ctrl_bk=0; void interrupt ceas(__CPPARGS){ /* incrementeaza contorul */ count++; /* achitarea intreruperii */ outportb(0x20,0x20); } void interrupt ctrl_brk(__CPPARGS){ ctrl_bk=1; } void main(void){ /* salveaza vechii vectori de intrerupere */ oldint8 = getvect(INTR_8); oldint23 = getvect(INTR_23); /* dezactiveaza sistemul de intreruperi mascabile */ asm cli; /* seteaza noii vectori de intrerupere */ setvect(INTR_8, ceas); setvect(INTR_23,ctrl_brk); /*salveaza masca pentru primul 8259*/ oldmask_1=inportb(0x21); /*demascheaza intreruperea 0*/ outportb(0x21,oldmask_1 & 0x0fe); /* activeaza sistemul de intreruperi mascabile */ asm sti; /* bucla de prelucrare a programului principal */ clrscr(); while ((count<1000)&&(!ctrl_bk)){

if(count!=oldcount) if((count % 10)==0) { printf("A); oldcount=count; } } /* dezactiveaza sistemul de intreruperi mascabile */ asm cli; /* seteaza vechii vectori de intrerupere */ setvect(INTR_8, oldint8); setvect(INTR_23,oldint23); /*seteaza vechea masca pentru primul 8259*/ outportb(0x21,oldmask_1); /* activeaza sistemul de intreruperi mascabile */ asm sti; }

pagina 81:
Probleme propuse: 1. I8254 are spatiul de adresare intre 214h si 217h. Intrarea GATE0 este la +5 V, iar intrarea de CLK0 este legata la un circuit formator de impulsuri de la un comutator actionat manual. Sa se elaboreze un program care sa afiseze pe display un mesaj la fiecare zece actionari ale comutatorului si care sa se opreasca dupa 200 actionari ale acestuia. Programul se va scrie astfel incat numararea impulsurilor sa se faca de catre o rutina de tratare a intreruperilor de la ceasul sistem, iar afisarea mesajului sa se faca in programul principal.
/* IRQ10 se afla in al 2-lea controller de intreruperi I8259; adresele de start ale rutinelor de tratare a intreruperilor de la 8 la 15 (IRQ8...IRQ15) sunt programate de BIOS sa se gaseasca in vectorii de intrerupere de la 70h la 77h (70h pt IRQ8, 71h pt IRQ9,...) */ /* counter0 este in mod de timer(divizor); intrarea de CLK a acestuia este conectata la iesirea circuitului formator de impulsuri de la comutatorul actionat manual; incarcam numaratorul cu valoarea 1 (0x01) => => numaratorul va genera o intrerupere la fiecare actionare a comutatorului de catre operatorul uman */ #include <dos.h> #include <stdio.h> #include <conio.h> #define IRQ10 0x72 // adresa IRQ10 din tabela vectorilor de intrerupere #define CA 0x214

#ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif unsigned int count = 0;

void interrupt (*oldint10)(__CPPARGS); void InitNum(void) { outportb(CA+3, 0x34); // counter0 => mod2, octetul LSB si apoi MSB outportb(CA, 0x01); // LSB outportb(CA, 0x00); // MSB } void interrupt handler_IRQ(__CPPARGS) // se genereaza intrerupere la { // fiecare actionare manuala a comutatorului count++; outportb(0x0A0, 0x20); // achitam intreruperea } void main(void) { oldint10 = getvect(IRQ10); disable(); setvect(IRQ10, handler_IRQ); unsigned char masca_initiala = inportb(0x0A1); // demascam IRQ10 din al 2-lea controller de intreruperi al carui // cuvant de control este la adresa 'A1h' outportb(0x0A1, masca_initiala & 0x0FB); enable(); InitNum(); clrscr(); while( !kbhit() && count<200) { gotoxy(1, 1); printf("Nr actionari comutator %d", count); if (count!=0 && count%10==0) printf("\n\nAu trecut 10 actionari manuale ale comutatorului."); } disable(); setvect(IRQ10, oldint10); outportb(0x0A1, masca_initiala); // refacem masca initiala enable(); }

2. I8254 are spatiul de adresare intre 214h 217h. Intrarile GATE pentru numaratoare sunt la +5 V iar intrarea de ceas de la NUM0 este legata la un generator de impulsuri cu frecventa 5MHz. Presupunem ca orice iesire OUTi poate fi conectata la oricare dintre canalele de intreruperi ale circuitului I8259 si de asemenea la intrarea CLK a urmatorului numarator. Intr-o aplicatie de achizitie de date este necesar ca o intrare analogica sa fie esantionata la 10ms, a doua intrare analogica la aproximativ 200 ms iar a treia la 1000s. Sa se elaboreze un program care programeaza I8254 astfel incat sa genereze intreruperi pe nivelurile 10, 11 si 15 (al doilea circuit I8259 de la un calculator compatibil IBM PC/AT), fiecarui numarator corespunzandu-i una din intreruperile de mai sus. Simularea achizitiei de date la intervalele specificate se va face afisand caracterul * la primul interval de timp, $ la al doilea interval de timp si @ la al treilea interval de timp. Programul poate fi oprit prin CTRL-BREAK. Sa se deseneze schema de cascadare a numaratoarelor si de conectare la canalele de intrerupere.
#include <dos.h> #include <stdio.h> #include <conio.h> /* IRQ10 se afla in al 2-lea controller de intreruperi I8259; adresele de start ale rutinelor de tratare a intreruperilor de la 8 la 15 (IRQ8...IRQ15) sunt programate de BIOS sa se gaseasca in vectorii de intrerupere de la 70h la 77h (70h pt IRQ8, 71h pt IRQ9,...) */ #define #define #define #define IRQ10 0x72 // adresa IRQ10 din tabela vectorilor de intrerupere IRQ11 0x73 IRQ15 0x77 IRQ_CTRL_BREAK 0x23 0x214

#define CA

#ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif int count = 0, void void void void interrupt interrupt interrupt interrupt ctrl_brk = 0; (*oldint10)(__CPPARGS); (*oldint11)(__CPPARGS); (*oldint15)(__CPPARGS); (*oldint_ctrl_break)(__CPPARGS);

void InitNum(void) // setam cele 3 numaratoare ca timere (divizoare) { outportb(CA+3, 0x34); outportb(CA+3, 0x74); outportb(CA+3, 0xB4); // incarc NUM2 cu 5000 = 0x1388 outportb(CA+2, 0x88); outportb(CA+2, 0x13); // incarc NUM1 cu 20 = 0x0014 outportb(CA+1, 0x14); outportb(CA+1, 0); // incarc num0 cu 50000 = 0x0C350 outportb(CA, 0x50); // LSB outportb(CA, 0x0C3); // MSB }

void interrupt irqa(__CPPARGS) { printf(" * "); count++; outportb(0x0A0, 0x20); // achitam intreruperea } void interrupt irqb(__CPPARGS) { printf(" $ "); count++; outportb(0x0A0, 0x20); } void interrupt irqf(__CPPARGS) { printf(" @ "); count++; outportb(0x0A0, 0x20); } void interrupt intr_ctrl_break(__CPPARGS) { // se apeleaza in momentul apasarii tastelor "CTRL_BREAK" ctrl_brk = 1; outportb(0x20, 0x20); // achitarea intreruperii } void main(void) { oldint10 = getvect(IRQ10); oldint11 = getvect(IRQ11); oldint15 = getvect(IRQ15); oldint_ctrl_break = getvect(IRQ_CTRL_BREAK); disable(); setvect(IRQ10, irqa); setvect(IRQ11, irqb); setvect(IRQ15, irqf); setvect(IRQ_CTRL_BREAK, intr_ctrl_break); unsigned char masca_initiala = inportb(0x0a1); // demascam cele 3 intreruperi (IRQ15, IRQ11, IRQ10) din al 2-lea // controller de intreruperi al carui cuvant de control este la adresa 'A1h' outportb(0x0A1, masca_initiala & 0x73); enable(); InitNum(); clrscr(); while(ctrl_brk == 0) { if(count) printf("Tratare intrerupere..."); } disable(); setvect(IRQ10, oldint10); setvect(IRQ11, oldint11); setvect(IRQ15, oldint15);

setvect(IRQ_CTRL_BREAK, oldint_ctrl_break); outportb(0x0A1, masca_initiala); // refacem masca initiala enable(); }

Varianta 2

#include <stdio.h> #include <dos.h> #include <conio.h> #define INTR_72 0x72/*Intreruperea IRQ10 de la I8254*/ #define INTR_73 0x73/*Intreruperea IRQ11 de la I8254*/ #define INTR_77 0x77/*Intreruperea IRQ15 de la I8254*/ #define CA 0x214 #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif unsigned char oldmask_1=0; int count0=0, count1=0, count2=0,oldcount0=0, oldcount1=0, oldcount2=0; void interrupt ( *oldint72)(__CPPARGS); void interrupt ( *oldint73)(__CPPARGS); void interrupt ( *oldint77)(__CPPARGS); void InitNum0 outportb outportb outportb } void InitNum1 outportb outportb outportb } void InitNum2 outportb outportb outportb } (void){ (CA+3, 0x34); (CA,0x50); (CA,0xc3); (void){ (CA+3, 0x74); (CA+1,0x14); (CA+1,0x00);

(void){ (CA+3, 0xb4); (CA+2,0x5); (CA+2,0x00);

/* rutina de tratare a intreruperii de la contorul 0 al I8254*/ void interrupt irq10(__CPPARGS){ /* incrementeaza contorul */ count0++; /* achitarea intreruperii */ outportb(0xa0,0x20); } /* rutina de tratare a intreruperii de la contorul 1 al I8254*/ void interrupt irq11(__CPPARGS){ /* incrementeaza contorul */ count1++; /* achitarea intreruperii */ outportb(0xa0,0x20); } /* rutina de tratare a intreruperii de la contorul 2 al I8254*/ void interrupt irq15(__CPPARGS){ /* incrementeaza contorul */ count2++; /* achitarea intreruperii */ outportb(0xa0,0x20); }

void main(void){ /* salveaza vechiul vector de intrerupere */ oldint72 = getvect(INTR_72); oldint73 = getvect(INTR_73); oldint77 = getvect(INTR_77); /* dezactiveaza sistemul de intreruperi mascabile*/ disable(); /* seteaza noul vector de intrerupere */ setvect(INTR_72, irq10); setvect(INTR_73, irq11); setvect(INTR_77, irq15); /*salveaza masca pentru primul 8259*/ oldmask_1=inportb(0x0a1); /*demascheaza intreruperea 0*/ outportb(0x0a1,oldmask_1 & 0x0fb); outportb(0x0a1,oldmask_1 & 0x0f7); outportb(0x0a1,oldmask_1 & 0x0ef); 7

/* activeaza sistemul de intreruperi mascabile */ enable(); clrscr(); InitNum2(); InitNum1(); InitNum0(); /* bucla de prelucrare a programului principal */ while (!kbhit()){/*se opreste la apasarea oricareai taste*/ if(count){ disable(); oldcount0 = count0; count0 = 0; oldcount1 = count1; count1 = 0; oldcount2 = count2; count2 = 0; enable(); if (oldcount0 == 1){ printf(*); } if (oldcount1 == 1){ printf($); } if (oldcount2 == 1){ printf(@); }

} } /* dezactiveaza sistemul de intreruperi mascabile */ disable(); /* seteaza vechii vectori de intrerupere */ setvect(INTR_72, oldint10); setvect(INTR_73, oldint11); setvect(INTR_77, oldint15); /*seteaza vechea masca pentru primul 8259*/ outportb(0x0a1,oldmask_1); /* activeaza sistemul de intreruperi mascabile*/ enable();} 8

3. Elaborati o schema bloc de masura si un program pentru determinarea si afisarea vitezei de rotatie instantanee a unui motor care are max. 3000 rot/min, utilizand I8254. Pe axul motorului exista un disc cu 10 fante echidistante si un dispozitiv optic care genereaza un impuls catre calculator la trecerea unei fante prin dreptul sau.
#include <dos.h> #include <stdio.h> #include <conio.h> /* IRQ10 se afla in al 2-lea controller de intreruperi I8259; adresele de start ale rutinelor de tratare a intreruperilor de la 8 la 15 (IRQ8...IRQ15) sunt programate de BIOS sa se gaseasca in vectorii de intrerupere de la 70h la 77h (70h pt IRQ8, 71h pt IRQ9,...) */ #define IRQ10 0x72 // adresa IRQ10 din tabela vectorilor de intrerupere #define CA 0x214

#ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif unsigned int count = 0, impulsuri = 0; void interrupt (*oldint10)(__CPPARGS); void InitNum(void) // setam cele 3 numaratoare { /* se seteaza I8254 astfel incat sa genereze o intrerupere o data la 50 ms; pt aceasta folosim 2 countere ca fiind timere, care trebuie sa numere pana la 250.000 pt a obtine o intrerupere la 50ms => valorile scrise in cele 2 numaratoare sunt: -counter 2 = 1000 = 0x03E8 => LSB=0xE8 si MSB=0x03 -counter 1 = 250 = 0x00FA => LSB=0xFA si MSB=0x00 aceste countere sunt descrescatoare si cand ajung la 0 dau intrerupere I8254 are frecventa de 5 MHz */ outportb(CA+3, 0x0B4); // counter2 => mod2, octetul LSB si apoi MSB outportb(CA+2, 0x0E8); // LSB outportb(CA+2, 0x03); // MSB outportb(CA+3, 0x74); // counter1 => mod2, octetul LSB si apoi MSB outportb(CA+1, 0x0FA); // LSB outportb(CA+1, 0x00); // MSB /* counter0 este in mod de numarare; intrarea de CLK a acestuia este conectata la iesirea dispozitivului optic care genereaza impulsuri (cate 500 de impulsuri/sec daca motorul are turatia maxima de 3000 rot/min); el numara practic impulsurile primite de la dispozitivul optic */ outportb(CA+3, 0x30); // counter0 => mod0, octetul LSB si apoi MSB outportb(CA, 0x00); // LSB outportb(CA, 0x00); // MSB }

void interrupt handler_IRQ(__CPPARGS) // din 50 ms in 50 ms { // la fiecare 20 de intreruperi => 1 secunda count++; /* daca motorul are turatia maxima de 3000 rot/min => dispozitivul optic genereaza catre calculator (catre numaratorul 0) 30000 impulsuri/min, adica 500 implusuri/sec */ if (count % 20 == 0) // citim valoarea numaratorului 0 { // citim valoarea numaratorului 0, pe care il setam in mod0 cu buffer-are outportb(CA+3, 0x00); unsigned char lsb = inportb(CA+1); unsigned char msb = inportb(CA+1); unsigned int val_num0 = ((0x0000 | msb) << 8) | lsb; impulsuri = 65536 - val_num0 + 1; // cate impulsuri/sec a primit // incarcam din nou NUM0, pt a numara in urmatoarea secunda nr de turatii outportb(CA+3, 0x30); // counter0 => mod0 cu LSB si apoi MSB outportb(CA+1, 0x00); outportb(CA+1, 0x00); } outportb(0x0A0, 0x20); // achitam intreruperea } void main(void) { oldint10 = getvect(IRQ10); disable(); setvect(IRQ10, handler_IRQ); unsigned char masca_initiala = inportb(0x0A1); // demascam IRQ10 din al 2-lea controller de intreruperi al carui // cuvant de control este la adresa 'A1h' outportb(0x0A1, masca_initiala & 0x0FB); enable(); InitNum(); clrscr(); while( !kbhit() ) { gotoxy(1, 1); printf("Count %d", count); if(count!=0 && count%20 == 0) // afisam din secunda in secunda printf("\n\nTuratie motor de %d rot/sec.", impulsuri/10); } disable(); setvect(IRQ10, oldint10); outportb(0x0A1, masca_initiala); // refacem masca initiala enable(); }

10

Varianta 2

#include <dos.h> #include <stdio.h> #include <conio.h> #define #define #define #define INTR_0A 0x72 INTR_0B 0x73 INTR_0F 0x77 CA 0x214

#ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif unsigned char oldmask_1 = 0; int count = 0; void interrupt (*oldint0a)(__CPPARGS); void interrupt (*oldint0b)(__CPPARGS); void interrupt (*oldint0f)(__CPPARGS); void InitNum(void) { outportb(CA+3, 0x34); ; outportb(CA+3, 0x74); ; outportb(CA+3, 0xB4); ; // incarc num2 cu 5000 outportb(CA+2, 0x88); outportb(CA+2, 0x13); // incarc num1 cu 20 outportb(CA+1, 0x14); outportb(CA+1, 0); // incarc num0 cu 50000 = 0x0c350 outportb(CA, 0x50); // LSB outportb(CA, 0x0c3); // MSB } void interrupt irqa(__CPPARGS) { printf(" * "); count++; outportb(0x0a0, 0x20); } void interrupt irqb(__CPPARGS) { printf(" $ "); 11

count++; outportb(0x0a0, 0x20); } void interrupt irqf(__CPPARGS) { printf(" @ "); count++; outportb(0x0a0, 0x20); } void main(void) oldint0a = oldint0b = oldint0f = { getvect(INTR_0A); getvect(INTR_0B); getvect(INTR_0F);

disable(); setvect(INTR_0A, irqa); setvect(INTR_0B, irqb); setvect(INTR_0F, irqf); oldmask_1 = inportb(0x0a1); outportb(0x0a1, oldmask_1 & 0x73); // pt. intr. A enable(); clrscr(); InitNum(); while(!kbhit()) if(count) printf("Asa baaaaaa"); disable(); setvect(INTR_0A, oldint0a); setvect(INTR_0B, oldint0b); setvect(INTR_0F, oldint0f); outportb(0x0a1, oldmask_1); enable(); }

Pr rezolvata- pag 82
Se cere implementarea controller-ului simplu PID prezentat la _2.2.2, considerand rata de esantionare pentru calcule de 0.01 secunde (10 ms). Pentru generarea bazei de timp se va utiliza un I8254 cu spatiul de adresare intre 214h 217h, intrarea GATE0 este la +5 V, intrarea de ceas de la NUM0 este conectata la un generator de impulsuri cu frecventa 5MHz iar iesirea OUT0 este conectata la intrarea IRQ5 de la primul controller I8259A al PC. Modul de lucru pentru numaratorul 0 va fi 2 iar valoarea initiala care se va incarca in numarator este 10 000 000ns /200ns = 50 000 = c350h. In programul prezentat in continuare, comunicatia intre rutina de tratare si programul utilizator se face prin variabila partajata contor: rutina de tratare a intreruperii incrementeaza variabila; programul utilizator, asteapta ca variabila sa fie diferita de 0: _ daca este 1 efectueaza calculele (a trecut perioada T) si ii atribuie valoarea 0; _ daca este mai mare decat 1 afiseaza eroare si termina programul deoarece programul principal nu se executa suficient de rapid pentru a se sincroniza cu

12

dispozitivul extern.
/*functia can achizitioneaza de la convertorul analog numeric, calculeaza si returneaza valoarea erorii e; este dependenta de hardware utilizat de exemplu poate fi scrisa pentru ADA2100*/ /*functia cna care primeste la intrare corectia (valoarea de actionare) si o transmite la convertorul numeric analogic; este dependenta de hardware utilizat de exemplu poate fi scrisa pentru ADA2100 */ #include <stdio.h> #include <dos.h> #include <conio.h> #define INTR_0d 0x0d/*Intreruperea IRQ5 de la I8254*/ #define CA 0x214 #define KPVAL 1.0 #define KIVAL 0.8 #define KDVAL 0.3 #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif unsigned char oldmask_1=0; int count=0,oldcount=0; float s, kp, ki, kd, en, enold, mn; extern float can(void); extern void cna(float mn); void interrupt ( *oldint0d)(__CPPARGS); void InitNum0 (void){ outportb (CA+3, 0x34); outportb (CA,0x50); outportb (CA,0xc3); } /* rutina de tratare a intreruperii de la contorul 0 al I8254*/ void interrupt irq5(__CPPARGS){ /* incrementeaza contorul */ count++; /* achitarea intreruperii */ outportb(0x20,0x20); } void main(void){ s = 0.0; kp = KPVAL; ki = KIVAL; kd = KDVAL; /* salveaza vechiul vector de intrerupere */ oldint0d = getvect(INTR_0d); /* dezactiveaza sistemul de intreruperi mascabile*/ disable(); /* seteaza noul vector de intrerupere */ setvect(INTR_0d, irq5); /*salveaza masca pentru primul 8259*/ oldmask_1=inportb(0x21); /*demascheaza intreruperea 0*/ outportb(0x21,oldmask_1 & 0x0df); /* activeaza sistemul de intreruperi mascabile */ enable(); clrscr(); enold = can(); InitNum0(); /* bucla de prelucrare a programului principal */ while (!kbhit()){/*se opreste la apasarea oricareai taste*/ if(count){ disable();

13

oldcount = count; count = 0; enable(); if (oldcount == 1){ en = can(); s = s+en; mn = kp*en + ki*s + kd * (en - enold); cna(mn); enold = en; } else{ printf (Eroare fatala, lipsa sincronizare); break; } } } /* dezactiveaza sistemul de intreruperi mascabile */ disable(); /* seteaza vechii vectori de intrerupere */ setvect(INTR_0d, oldint0d); /*seteaza vechea masca pentru primul 8259*/ outportb(0x21,oldmask_1); /* activeaza sistemul de intreruperi mascabile*/ enable(); }

pagina 84:
Problema propusa Scrieti functia delay_ms(unsigned int t) care realizeaza o intarziere de aproximativ t milisecunde, indiferent de procesorul PC-ului, fara a reprograma ceasul sistem. Indicatie: se va utiliza numaratorul 0, care este preprogramat de catre BIOS, citind ciclic valoarea din contor, facand diferentele intre citiri succesive si calculand numarul de milisecunde
#include <dos.h> #include <stdio.h> #include <stdlib.h> #define F0 1193187 #define CA 0x040 unsigned int readtimer() { outportb(CA+3,0); //bufferare citire LSB+MSB unsigned int val = inportb(CA); val+=inportb(CA)*256; return val; } void delay_ms(unsigned int t) { unsigned long tt=0; unsigned int val,oldval; oldval = readtimer(); while((tt/F0)*1000<t) { val=readtimer(); if(val<oldval)

14

tt+=(oldval-val); else { tt+=(65535-val)+oldval; } oldval = val; //printf("%lu ",tt); } } void main(int argc, char* argv[]) { /* for(int i = 0; i<200;i++) { printf("Timer: %u,",readtimer()); } */ //printf("%d\n",argc); if(argc<2) printf("\nSETCLK <value>\n value in msa\n"); else { int val = atoi(argv[1]); delay_ms(val); printf("\nDelayed for %d ms",val); } } Var 2: #include #include #include #include <dos.h> <stdio.h> <conio.h> <stdlib.h>

#define F0 1193187 // frecventa (in Hz) de pe placa de baza a PC-ului #define CA 0x040 // adresa counterului 0 al BIOS-ului unsigned int ReadCounter() { // selectam numaratorul 0 al BIOS-ului, in modul de lucru 0 (adica oprire // la sfarsitul numararii = iesirea acestuia OUT0 nu este folosita), // cu buffer-are pt citire iesiri numarator outportb(CA+3, 0); //buffer-are citire LSB+MSB unsigned int val = inportb(CA); // citeste octetul LSB // citim octetul MSB, pe care il deplasam la stanga 8 pozitii, // si apoi il adunam la octetul LSB val+=inportb(CA)*256; return val; // returnam iesirea numaratorului 0 al BIOS-ului } void delay_ms(unsigned int t) { // "tt" = nr de impulsuri (DE NUMARARI) care au trecut de la // apelul acestei functii unsigned long tt = 0; unsigned int val, oldval;

15

oldval = ReadCounter(); // "tt / F0" = nr de secunde => inmultim cu 1000 pt a transforma in ms while (tt / F0 * 1000 < t) // cat timp nu au trecut "t" ms { val = ReadCounter(); if(val < oldval) tt += (oldval - val); else tt += (65535 - val) + oldval; oldval = val; } } void main() { clrscr(); struct time t; gettime(&t); printf("The current time before delay is: %2d:%02d:%02d.%02d", t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund); delay_ms(1000); gettime(&t); printf("\n\nThe current time after delay is: %2d:%02d:%02d.%02d", t.ti_hour, t.ti_min, t.ti_sec, t.ti_hund); printf("\n\nApasati o tasta pentru a parasi programul..."); getch(); } Varianta #include #include #include 3 <dos.h> <stdio.h> <stdlib.h>

#define F0 1193187 #define CA 0x040 long oldval=-1, val=-1, t; unsigned int readtimer() { outportb(CA+3,0); //bufferare citire LSB+MSB unsigned int val = inportb(CA); val+=inportb(CA)*256; return val; } void interrupt handler() { if(oldval<0) { //oldval = readtimer(); outportb(CA+3,0); //bufferare citire LSB+MSB oldval = inportb(CA); oldval+=inportb(CA)*256; } else { oldval = val;

16

//val = readtimer(); outportb(CA+3,0); //bufferare citire LSB+MSB val = inportb(CA); val+=inportb(CA)*256; if(val<oldval) t = oldval - val; else t = (65535-val) + oldval; } } void main(int argc, char* argv[]) { int rot; clrscr(); //setarea noului vector de tratare a intreruperii do{ rot = 0.1/(t*0.055); gotoxy(1,1); printf("%d rot/s", rot); ch = getch(); }while(ch!=13); //revenire la vechiul vector de tratare a intreruperii }

pag 100:
Problema propusa Sa se adapteze programul de prezentat la _4.3.4 si se scrie functiile can() si cna()pentru cazul in care sistemul de achizitie de date si control este realizat cu ADA2100.

Rezolvare:
Prb pg 100 #include <stdio.h> #include <dos.h> #include <conio.h> #define INTR_0d 0x0d/*Intreruperea IRQ5 de la I8254*/ #define CA 0x214 #define ref 0 # define KPVAL 1.0 # define KIVAL 0.8 # define KDVAL 0.3 #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif unsigned char oldmask_1=0; int count=0,oldcount=0; float s, kp, ki, kd, en, enold, mn; /*functia can achizitioneaza de la convertorul analog numeric, calculeaza si returneaza valoarea erorii e; este dependenta de hardware utilizat de exemplu poate fi scrisa pentru ADA2100*/ float can(void) {

17

int var1,var2; float rez; outportb(CA + 1, 0); outportb(CA + 4, 0); while((inport(CA)& (0x80)) != 0x80); var1=inport(CA + 4); var2=inport(CA + 5); rez=(var1 * 16) + (var2 / 16); rez=(rez - 2048) * 4.8828 / 1000.0; rez=ref - rez; return rez; } /*functia cna care primeste la intrare corectia (valoarea de actionare) si o transmite la convertorul numeric analogic; este dependenta de hardware utilizat de exemplu poate fi scrisa pentru ADA2100 */ void cna(float mn) { mn=mn * 1000.0 / 4.8828 - 2048; outportb(CA + 8, mn & 255); outportb(CA + 9, mn / 256); } void interrupt ( *oldint0d)(__CPPARGS); void InitNum0 (void){ outportb (CA+3, 0x34); outportb (CA,0x50); outportb (CA,0xc3); } /* rutina de tratare a intreruperii de la contorul 0 al I8254*/ void interrupt irq5(__CPPARGS){ /* incrementeaza contorul */ count++; /* achitarea intreruperii */ outportb(0x20,0x20); } void main(void){ s = 0.0; kp = KPVAL; ki = KIVAL; kd = KDVAL; /* salveaza vechiul vector de intrerupere */ oldint0d = getvect(INTR_0d); /* dezactiveaza sistemul de intreruperi mascabile*/ disable(); /* seteaza noul vector de intrerupere */ setvect(INTR_0d, irq5); /*salveaza masca pentru primul 8259*/ oldmask_1=inportb(0x21); /*demascheaza intreruperea 0*/ outportb(0x21,oldmask_1 & 0x0df); /* activeaza sistemul de intreruperi mascabile */ enable(); clrscr(); enold = can(); InitNum0(); /* bucla de prelucrare a programului principal */ while (!kbhit()){/*se opreste la apasarea oricareai taste*/ if(count){ disable(); oldcount = count; count = 0; enable(); if (oldcount == 1){ en = can(); s = s+en;

18

mn = kp*en + ki*s + kd * (en - enold); cna(mn); enold = en; } else{ printf (Eroare fatala, lipsa sincronizare); break; } } } /* dezactiveaza sistemul de intreruperi mascabile */ disable(); /* seteaza vechii vectori de intrerupere */ setvect(INTR_0d, oldint0d); /*seteaza vechea masca pentru primul 8259*/ outportb(0x21,oldmask_1); /* activeaza sistemul de intreruperi mascabile*/ enable(); }

pag 114:
Implementarea unui dispecer utilizand modelul descris in figura 5.2.4-1.
#include <dos.h> #include <stdio.h> #include <conio.h> #define INTR_8 0x08

#ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif unsigned char oldmask_1 = 0,mask,tab[40]; void interrupt (*oldint8)(__CPPARGS); int tick = 0, count = 0; void cit(void) { printf("Masca :");scanf("%c",&mask); } void interrupt ceas(__CPPARGS) { cit(); tick++;

19

outportb(0x20, 0x20); } void a(void) { printf("Task-ul A a fost } void b(void) { printf("Task-ul B a fost } void c(void) { printf("Task-ul C a fost } void d(void) { printf("Task-ul D a fost } void e(void) { printf("Task-ul E a fost } void f(void) { printf("Task-ul F a fost } void g(void) { printf("Task-ul G a fost } void h(void) { printf("Task-ul H a fost } void decode(int k) { switch(k) { case 1: a();break; case 2: b();break; case 3: c();break; case 4: d();break; case 5: e();break; case 6: f();break; case 7: g();break; case 8: h();break; } }

activat la %d\n", tick);

activat la %d\n", tick);

activat la %d\n", tick);

activat la %d\n", tick);

activat la %d\n", tick);

activat la %d\n", tick);

activat la %d\n", tick);

activat la %d\n", tick);

void initTab(void) { for(int j=1;j<41;j++) { tab[j]=0; if(j%4==0) tab[j]=tab[j]|0xc0; if(j%5==0) tab[j]=tab[j]|0x30; if(j%8==0) tab[j]=tab[j]|0x0c; if(j%10==0) tab[j]=tab[j]|0x02; if(j%20==0)

20

tab[j]=tab[j]|0x01; } } void main(void) { oldint8 = getvect(INTR_8); disable(); setvect(INTR_8, ceas); oldmask_1 = inportb(0x21); outportb(0x21, oldmask_1 & 0x0fe); enable(); clrscr(); initTab(); while(!kbhit()) { if(tick) { if(tick>40) count=tick%40; else count=tick; unsigned char temp=tab[count]; temp &= mask; for(int i=0;i<8;i++) { unsigned char k = 0; k = temp << i; k = k & 0x80; if(k !=0) { decode(i+1); break; } } } } disable(); setvect(INTR_8, oldint8); outportb(0x21, oldmask_1); enable(); }

21

Problema examen:
#include<dos.h> #include<conio.h> #include<stdio.h> //la placa canal1 2-10V->0-7MW //----||--- canal2 2-10V->0-100metrii cub/secunda #define #define #define #define #define INTR5 0x0D INTR11 0x73h BA 0x280 URCA 0x1 COBOARA 0x2

//adresa de start a placii ada2100

#ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif int display; unsigned char oldmask_1 = 0; void interrupt (*oldint5)(__CPPARGS); void interrupt (*oldint11)(__CPPARGS); void main(void) { int grupede200=4; outportb(BA+3,90); //initializez placa oldint5=getvect(INTR5); oldint11=getvect(INTR11); //salveaza masca ptr primul timer 8254 0x21-port de control oldmask1=inportb(0x21); // asm cli; sau disable(); disable(); setvect(INTR5,IRQ5); setvect(INTR11,IRQ11); //0x21 port de control ptr primul modul de intreruperi outportb(0x21,oldmask1&0xEF); //0xA1 port de control ptr al doilea modul de intreruperi unsigned char oldmask2=inportb(0xA1); outportb(0xA1,oldmask2&0xF3); //initializare timere //timer 0 outportb(BA+0x17,0x34); //se scrie in Control Word //0011 1000 00-timer 0, mod 4 binar, outportb(BA+0x14,0x00); //incarca lsb outportb(BA+0x14,0x0f); // incarca msb timer0=0x0f00 //timer 1 outportb(BA+0x17,0x74); //se scrie in Control Word //0111 1000 01-timer1 ,lsb se incarca prima data, mod4,numara binar outportb(BA+0x15,0x4c);//incarca lsb outportb(BA+0x15,0x0); //incarca msb timer1=0x04c //init timer 2 outportb(BA+0x17,0x0b4); outportb(BA+0x16,0x0ff); outportb(BA+0x16,0x0ff); asm sti;

22

while(!kbhit()) { if(display { putere=f(int tensiune);//formule ptr calculul puterii si debit=q(int tensiune); //debit din tensiunea citita(trebuie implementate) printf("\rdebit=%fmc putere=%cMW turatie=%d",putere,debit,turatie); display=0; } } asm cli; setvect(INTR5,oldint8); setvect(INTR11,oldint11); outportb(0x21,oldmask1); outportb(0xA1,oldmask2); asm sti; } //end main cred void interrupt IRQ5(__CPPARGS) { int MSB,LSB,putere,debit; //citeste canal 1 outportb(BA+0x1,0x0); outportb(BA+0x4,0x0); //start conv while ((inportb(BA) & 0x80)!=0x80); MSB=inportb(BA+0x4); LSB=inportb(BA+0x5); //citire 1 putere=MSB*16+LSB/16; 0..4055->2..10V //citeste canal 2 outportb(BA+0x1,0x0); outportb(BA+0x4,0x0); //start conv while ((inportb(BA) & 0x81)!=0x81); MSB=inportb(BA+0x4); LSB=inportb(BA+0x5); //citire 1 debit=MSB*16+LSB/16; 0..4055->2..10V outportb(0x20,0x20); //achitare intrerupere } void interrupt IRQ11(__CPPARGS) { int MSB,LSB,reading,impulsuri,turatie; display=1; grupede200--; if (grupede200==0) { //a trecut o secunda si achizitionam turatia outportb(BA+20,0); LSB=inportb(BA); MSB=inportb(BA); reading=MSB*256+LSB; impulsuri=65536-reading+1; turatie=impulsuri/100; if (turatie<190) outportb(BA,URCA); else if (turatie>210) outportb(BA,COBOARA); outportb(BA+20,30); outportb(BA+20,0); outportb(BA+20,0); grupede200=4; } outportb(0xA0,0x20); }

23

/* Fie o aplicatie HRT cu task-urile periodice A, B, C, D cu perioara de lansare in executie la intervale de timp: PA=200ms, PB=100ms, PC=150ms, PD=50ms. Tick-ul sistem este la 50 ms, iar timpii de executie in cazul cel mai defavorabil pentru task-uri sunt: eA=15ms, eB=10ms, eC=21ms, eD=15ms. Task-urile sunt fazate la momentul 0 (la tick-ul 0, toate task-urile solicita executia). Timpul impus pentru terminarea executiei fiecarui task este sfarsitul perioadei asociate. Daca tick-ul ceasul de timp real este la 50 ms => fiecare task se va executa astfel: - task-ul A la fiecare 4 tick-uri - task-ul B la fiecare 2 tick-uri - task-ul C la fiecare 3 tick-uri - task-ul D la fiecare tick Rezulta astfel ca c.m.m.m.c(1, 2, 3, 4) = 12. INDICATIE: Rutina de tratare a intreruperii de ceas trebuie sa comunice cu programul utilizator (dispecer de lansare a celorlalte task-uri) printr-un cuvant care indica ce task-uri trebuie lansate. Programul utilizator va lansa rutinele asociate task-urilor in ordinea prioritatilor. */
#include <dos.h> #include <stdio.h> #include <conio.h> #define INTR_CEAS 0x08 // intreruperea de ceas real de pe placa de baza, // controlat de BIOS #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif unsigned char masca=0x0FF, tabela[12]; void interrupt (*oldint8)(__CPPARGS); int tick = 0, count = 0; void interrupt intr_ceas(__CPPARGS) // se apeleaza din 55 ms in 55 ms { // nu putem apela functii in rutina de intrerupere tick++; outportb(0x20, 0x20); // achitam intreruperea } void a(void) { printf("Task-ul A a fost activat la %d\n", tick); } void b(void) { printf("Task-ul B a fost activat la %d\n", tick); } void c(void) { printf("Task-ul C a fost activat la %d\n", tick);

24

} void d(void) { printf("Task-ul D a fost activat la %d\n", tick); } void decode(int k) { switch(k) { case 1: a(); break; case 2: b(); break; case 3: c(); break; case 4: d(); break; } } void Init_Counter0() // se seteaza pt a genera o intrerupere la 50 ms { // incarcam Counter0 cu valoarea 59660 = 0xE90C /* outportb(0x43, 0x36); // counter0, mod3, R/W lsb apoi MSB outportb(0x40, 0x0C); outportb(0x40, 0xE9); */ asm { mov al, 36h out 43h, al mov ax, 59660 out 40h, al mov al, ah out 40h, al } } void Init_Tabela(void) // intializare tabela task-uri in numar de 4: A ... D { // cele 4 task-uri se afla in tetrada superioara a fiecarui octet // din vectorul "tabela" for(int j=0;j<12;j++) // c.m.m.m.c(1, 2, 3, 4) = 12 { tabela[j]=0; if (j%4 == 0) // la 4 tick-uri avem task-ul A tabela[j] = tabela[j] | 0x80; if (j%2 == 0) // la 2 tick-uri avem task-ul B tabela[j] = tabela[j] | 0x40; if (j%3 == 0) // la 3 tick-uri avem task-ul C tabela[j]= tabela[j] | 0x20; tabela[j] = tabela[j] | 0x10; // la 1 tick avem task-ul D } } void main(void) { oldint8 = getvect(INTR_CEAS); disable(); setvect(INTR_CEAS, intr_ceas);

25

unsigned char masca_intreruperi = inportb(0x21); // demascam intreruperea IRQ0, asociata implicit intreruperii de ceas real outportb(0x21, masca_intreruperi & 0x0FE); enable(); clrscr(); Init_Tabela(); // initilizam tabela celor 8 task-uri Init_Counter0(); while (!kbhit()) { if(tick) // s-a apelat cel putin o data rutina de intrerupere { count = tick % 12; unsigned char temp=tabela[count]; // vom prelua acele task-uri care au bitul 1 in "masca", dintre // care se va executa numai task-ul cu prioritatea cea mai mare temp &= masca; for(int i=0; i<4;i++) // masca contine 8 biti de la 0 la 7, insa { // parcurgem doar tetrada superioara, deoarece avem 4 task-uri unsigned char k = temp << i; k = k & 0x80; // extragem msb-ul mastii "masca" // daca msb=1 (k=0x80) => activam numai acel task, aflat pe // coloana "i" din "tabela", deoarece are prioritatea cea mai mare if(k != 0) { decode(i+1); } break; // celelalte task-uri cu prioritate mai mica // nu se mai executa

} } } // de la "while(!kbhit())" disable(); setvect(INTR_CEAS, oldint8); outportb(0x21, masca_intreruperi); enable(); // restauram ceasul sistem la rata de intrerupere initiala asm { mov al, 36h out 43h, al xor al, al out 40h, al out 40h, al } }

26

Problema examen
/* Se cere realizarea unei aplicatii pentru monitorizare, calcule si actionare in vederea indeplinirii conditiilor de functionare ale unui echipament compus din PC industrial si subsisteme cu I/E. Echipamnetul este utilizat ca server pentru achizitie de date si comenzi intr-o centrala nucleara si este amplasat intr-un dulap prevazut cu ventilator pentru evitarea supraincalzirii incintei. Echipamnetul si ventilatorul sunt alimentate de la reteaua de alimentare industriala cu tensiunea UE [0, 250] si curent I [0, 25A]. Tensiunea si curentul pot fi masurate utilizand semnale de la 2 traductoare care ofera la iesire 2 - 10 mA, proportional cu marimile de intrare. Ventilatorul are o turatie de 500 rot/min, atinsa in 2 sec de la pornire. Un dispozitiv electronic genereaza 100 impulsuri TTL, la fiecare rotatie iar pornirea/oprirea se face printr-un releu exterior care poate fi comandat pe nivel cu iesire numerica (1-pornit, 0-oprit). Starea ventilatorului (daca este pornit sau oprit ) este indicata printr-un semnal de tensiune 50V, daca ventilatorul este pornit, 0V daca este oprit. Temperatura T in interioarul dulapului este masurata cu un traductor care ofera la ieisre 0 - 1,25V, proportional cu temperatura, calibrat pentru T=[0, 100] grade Celsius. Pentru monitorizare si controlul conditiilor de fucntionare a echipamentului, clientul va solicita un sistem realizat cu PC-ul si modul de achizitie ADA 2100. Configuratia ADA2100 va fi astfel: - Domeniul de intrare CAN 0-10V, single ended - Tensiunea se va citi pe canalul 0 al ADA2100 - Curentul se va citi pe canalul 1 al ADA2100 - Temperatura se va citi pe canalul 2 al ADA2100 - Comanda pornirii/opririi ventilatorului se va face pe o iesire numerica (la alegere) - Detectia starii pornit/oprit a ventilatorului se va face pe o intrare numerica (la alegere) - Semnalul ]n impuls de la dispozitivul electronic de turatie este conectat la CLK0 al I8254 - CLK1 este conectata la un generator de impulsuri de 1 MHz - OUT1 este conectat? la CLK2 si la IRQ5 - OUT2 este conectat pe IRQ11 Se cere: 1. Schema bloc de conectare a circuitelor de intrare si comanda la canalele de I/E ale ADA2100 (conditionarea semnalelor) 2. Program cu urmatoarele functii (C/C++): - Initializare achizitie si intreruperi, in programul principal - Achizitia ciclica a marimilor analogice cu rata de esantionare 1ms, in rutina de tratare a intreruperii IRQ5, afisarea in programul principal a unor mesaje de atentionare daca tensiunea este in afara intervalului 220 Vca +- 10%, curentul >= 12A iar temperatura >= 45,5 C - Achizitie ciclica turatie ventilator la 1 sec, utilizand intreruperea IRQ11, afisarea unui mesaj de atentionare in programul principal daca turatia este mai mica de 450 rot/min. - Pornirea ventilatorului cand temperatura este >= 30,5 C si oprirea cand temperatura este <= 29,5C - Afisarea in programul principal, ciclic la 200ms, a tensiunii, curentului si temperatura, precum si a starii ventilatorului; valorile vor fi afisate utilizand filtre de tip fereastra glisanta, pe intervalul dintre

27

2 afisari succesive.
#include <stdio.h> #include <dos.h> #include <conio.h>

*/

/* IRQ5 se afla in primul controller de intreruperi I8259; adresele de start ale rutinelor de tratare a intreruperilor de la 0 la 7 (IRQ0...IRQ7) sunt programate de BIOS sa se gaseasca in vectorii de intrerupere de la 08h la 0Fh (08h pt IRQ0, 09h pt IRQ1,...) */ #define IRQ5 0x0D // adresa IRQ5 din tabela vectorilor de intrerupere /* IRQ11 se afla in al 2-lea controller de intreruperi I8259 pe nivelul 3; adresele de start ale rutinelor de tratare a intreruperilor de la 8 la 15 (IRQ8...IRQ15) sunt programate de BIOS sa se gaseasca in vectorii de intrerupere de la 70h la 77h (70h pt IRQ8, 71h pt IRQ9,...) */ #define IRQ11 0x73 // adresa IRQ11 din tabela vectorilor de intrerupere #define BA 0x280 // adresa de baza a placii ADA 2100 #define CONTROL 0x91 // cuvantul de control cu care se initializeaza placa // Ch = output = 0 (portul C este pt intrari/iesiri // Cl = input = 1 digitale) // cuvant de control: 1001 0001 = 0x91 #ifdef __cplusplus #define __CPPARGS ... #else #define __CPPARGS #endif void interrupt ( *oldhandler_IRQ5)(__CPPARGS); void interrupt ( *oldhandler_IRQ11)(__CPPARGS); int count_IRQ5=-1, count_IRQ11=0, apel_IRQ5 = 0;; unsigned int impulsuri = 0, val_canal_A0=0, val_canal_A1=0, val_canal_A2=0; float buf_tensiune[200], buf_curent[200], buf_temperatura[200]; unsigned char val_canale_numerice, stare_ventilator; unsigned int citire_canal_analogic(unsigned char nr_canal, unsigned char gain) { // se seteaza adresele prin intermediul carora se comunica cu ADA 2100 unsigned int port_A = BA + 0x00; // port intrare unsigned int port_B = BA + 0x01; // port iesire unsigned int port_conversie12_A_N = BA + 0x04;//start conversie pe 12 biti unsigned int port_citire_MSB = BA + 0x06; unsigned int port_citire_LSB = BA + 0x07; // gain = amplificarea valorii analogice citite de pe placa ADA 2100 gain = gain / 2; // gain = gain >> 1; // se selecteza canalul analogic pe care-l citim si amplificarea outportb(port_B, (gain<<4) | nr_canal); // se inscrie la "BA+4" orice valoare pt a incepe conversia analog numerica outportb(port_conversie12_A_N, 0); // se scrie valoarea 0 (nu conteaza)

28

while(((inportb(port_A)) & (0x80))

!=

0x80);

// aici, s-a terminat conversia, deci se pot citi valorile achizitionate unsigned int LSB = inportb(port_citire_LSB); // se citeste octetul LSB unsigned int MSB = inportb(port_citire_MSB); // se citeste octetul MSB // se calculeaza rezultatul conversiei A => N unsigned int result = MSB*16 + LSB/16;// result = (MSB << 4) + (LSB >> 4); return result; } unsigned char citire_canale_numerice() // se citeste portul Ch { // scriem in cuvantul de control al porturilor outportb(BA+3, 89); unsigned char val = inportb(BA+2); return val; } void setare_canale_numerice(unsigned char valoare) // se scrie in portul Cl { outportb(BA+3, 89); outportb(BA+2, valoare); } void interrupt handler_IRQ5(__CPPARGS) { apel_IRQ5 = 1; count_IRQ5 ++; // din 1 ms in 1 ms

val_canal_A0 = citire_canal_analogic(0, 1); val_canal_A0 = val_canal_A0 * 2.4414 / 1000; // in volti // conversie in valori ingineresti // a = 15625 b = 0 Y=aX+b X=val_canal_A0 buf_tensiune[count_IRQ5] = 15625.0 * (float)val_canal_A0; val_canal_A1 = citire_canal_analogic(1, 1); val_canal_A1 = val_canal_A1 * 2.4414 / 1000; buf_curent[count_IRQ5] = 1562.5 * (float)val_canal_A1;

// b = 0

val_canal_A2 = citire_canal_analogic(2, 1); val_canal_A2 = val_canal_A2 * 2.4414 / 1000; buf_temperatura[count_IRQ5] = 80.0 * (float)val_canal_A2; // b = 0 // citim starea ventilatorului, aflata pe bitul lsb val_canale_numerice = citire_canale_numerice(); stare_ventilator = 0x01 & val_canale_numerice; // daca lsb=1 => pornit if(count_IRQ5 == 199) count_IRQ5=-1;// s-a apelat de 200 ori rutina IRQ5 /* se achita intreruperea => sistemul de operare este anuntat ca s-a termiat rutina de tratare intreruperi */ outportb (0x20, 0x20); // scrie la adresa 20h a primului controller I8259 // valoarea 20h (resetam flagurile);

void interrupt handler_IRQ11(__CPPARGS) // din 1 secunda in 1 secunda { // intr-o sec NUM0 nu ajunge niciodata la valoarea 0 count_IRQ11++; /* in fiecare secunda NUM0 primeste maxim 834 impulsuri (motorul are turatia de 8,34 rot/sec) de la dispozitivul electronic, care genereaza impulsuri catre NUM0;

29

daca NUM0 primeste sub 750 impulsuri/sec => motorul are turatie critica sub 450 rot/min */ // citim valoarea numaratorului 0, pe care il setam in mod0 cu buffer-are outportb(BA+0x17, 0x00); unsigned char lsb = inportb(BA+0x14); unsigned char msb = inportb(BA+0x14); unsigned int val_num0 = ((0x0000 | msb) << 8) | lsb; // val_num0 = msb*256 + lsb; impulsuri = 65536 - val_num0 + 1; // cate numarari a efectuat // incarcam din nou NUM0, pt a numara in urmatoarea secunda nr de turatii outportb(BA+0x17, 0x30); // counter0 => mod0 cu LSB si apoi MSB outportb(BA+0x14, 0x00); outportb(BA+0x14, 0x00); /* se achita intreruperea => sistemul de operare este anuntat ca s-a termiat rutina de tratare intreruperi */ outportb (0x0A0, 0x20);// scrie la adresa A0h a celui de-al 2-lea // controller I8259 valoarea 20h (resetam flagurile);

void unmask(unsigned char irq, unsigned int adr) // "irq" = nr intreruperii care se demascheaza { unsigned char masca = inportb(adr); // preluam masca intreruperilor // se deplaseaza la stanga octetul 00000001 cu "irq" pozitii unsigned char dirq = 0x01 << irq; // se calculeaza noua masca, obligand la resetarea bitului // corespunzator lui "irq" unsigned char newmask = masca & ~dirq; // se stabileste noua masca, in care intreruperea "irq" este dezactivata outportb(adr, newmask); } void mask(unsigned char irq, unsigned int adr) // "irq" = nr intreruperii care se mascheaza { unsigned char masca = inportb(adr); // preluam starile intreruperilor // se deplaseaza la stanga octetul 00000001 cu "irq" pozitii unsigned char dirq = 0x01 << irq; // se calculeaza noua masca, obligand la setarea bitului // corespunzator lui "irq" unsigned char newmask = masca | dirq; // se stabileste noua masca, in care intreruperea "irq" este activata outportb(adr, newmask); } void initADA2100(void) { // A - input, B - output, C - input/output, mode 0, active outportb(BA + 0x03, CONTROL); } // C - intrari/iesiri canale digitale; A - intrari canale analogice void set_timers() { unsigned int unsigned int unsigned int unsigned int

alfa = adr_c2 adr_c1 adr_c0

BA + = BA = BA = BA

0x17;// + 0x16; + 0x15; + 0x14;

adresa cuvantului de control al counterelor // adresa counter-ului 2 // adresa counter-ului 1 // adresa counter-ului 0

30

// divizor = timer outportb(alfa, 0xB4); // counter2 => mod2, octetul LSB si apoi MSB // incarcam 1000 = 0x03E8 outportb(adr_c2, 0xE8); // se seteaza valoarea de start (LSB) a counter-ului 1 outportb(adr_c2, 0x03); // se seteaza valoarea de start (MSB) a counter-ului 1 // divizor = timer outportb(alfa, 0x74); // counter1 => mod2, octetul LSB si apoi MSB // incarcam 1000 = 0x03E8 outportb(adr_c1, 0xE8); // se seteaza valoarea de start (LSB) a counter-ului 1 outportb(adr_c1, 0x03); // se seteaza valoarea de start (MSB) a counter-ului 1 outportb(alfa, 0x30); // counter0 => mod0, octetul LSB si apoi MSB outportb(adr_c0, 0x00); // se seteaza valoarea de start (LSB) a counter-ului 0 outportb(adr_c0, 0x00); // se seteaza valoarea de start (MSB) a counter-ului 0 } float medie_fer_glisanta(int i) // calculam media aritmetica a valorilor { // esantionate in 200 ms float suma=0; if (i == 1) for (int j=0; j<200; j++) suma += buf_tensiune[j]; else if (i == 2) for (int j=0; j<200; j++) suma += buf_curent[j]; else for (int j=0; j<200; j++) suma += buf_temperatura[j]; return (suma / 200.0); } void ascunde_cursor() { asm { mov ax, 0x0100 mov cx, 0x2607 int 0x10 } } void arata_cursor() { asm { mov ax, 0x0100 mov cx, 0x0506 int 0x10 } } void main(void) { // se citeste masca initiala a controlerului 1 de intreruperi unsigned char masca_initiala_1 = inportb(0x21); // se citeste masca initiala a controlerului 2 de intreruperi unsigned char masca_initiala_2 = inportb(0xA1); initADA2100(); // se initializeaza placa

31

// se mascheaza IRQ5 din controlerul 1 cu care lucreaza ADA2100 //mask(0x05, 0x21); // se mascheaza IRQ11 din controlerul 2 cu care lucreaza ADA2100 //mask(0x03, 0xA1); // se preiau vechii vectori de intrerupere oldhandler_IRQ5 = getvect(IRQ5); oldhandler_IRQ11 = getvect(IRQ11); disable(); // dezactivam intreruperile, pt a seta noii vectori // se seteaza noii vectori de intrerupere setvect(IRQ5, handler_IRQ5); setvect(IRQ11, handler_IRQ11); enable(); // se activeaza intreruperile cu noi vectori de intrerupere set_timers(); unmask(0x05, 0x21); // demascam IRQ5, pt a fi tratata de I8259 unmask(0x03, 0xA1); // demascam IRQ11 clrscr(); ascunde_cursor(); while( !kbhit() ) { if (apel_IRQ5 == 1) // din 1ms in 1 ms { if(buf_tensiune[count_IRQ5] < 198 || buf_tensiune[count_IRQ5] > 242) printf("\n\a\a\aATENTIUNE: Tensiune de: %f", buf_tensiune[count_IRQ5]); if(buf_curent[count_IRQ5] >= 12) printf("\n\a\a\aATENTIUNE: Curent de: %f", buf_curent[count_IRQ5]); if(buf_temperatura[count_IRQ5] >= 45.5) printf("\n\a\a\aATENTIUNE: Temperatura de: %f", buf_temperatura[count_IRQ5]); if(buf_temperatura[count_IRQ5] >= 30.5) // pornire ventilator { if(stare_ventilator == 0) { // daca e oprit => il pornim cu 1 pe bitul msb val_canale_numerice |= 0x80; setare_canale_numerice(val_canale_numerice); } } if(buf_temperatura[count_IRQ5] <= 29.5) // oprire ventilator { if(stare_ventilator == 1) { // daca e pornit => il oprim cu 0 pe bitul msb val_canale_numerice &= 0x7F; setare_canale_numerice(val_canale_numerice); } } if (count_IRQ5 == -1) // afisam din 200ms in 200ms { printf("\nTensiune: %f", medie_fer_glisanta(1)); printf("\nCurent: %f", medie_fer_glisanta(2));

32

printf("\nTemperatura: %f", medie_fer_glisanta(3)); printf("\nStare ventilator: %d", stare_ventilator); } } if (count_IRQ11 != 0) // a trecut cel putin o secunda { // din secunda in secunda if (count_IRQ11>2 && impulsuri<750) // rotatie critica sub 450 rot/min printf("\n\a\a\a\ATENTIUNE: Turatie ventilator critica de %d rot/min.", (impulsuri/100)*60); else printf("Turatie ventilator de %d rot/min.",(impulsuri/100)*60); } } // de la "while( !kbhit() )" arata_cursor(); disable(); // se restabilesc vectorii de intrerupere, care erau inainte // de pornirea programului setvect(IRQ5, oldhandler_IRQ5); setvect(IRQ11, oldhandler_IRQ11); // restabilim mastile initiale pt ambele intreruperi outportb(0x21, masca_initiala_1); outportb(0xA1, masca_initiala_2); enable(); }

33