/* ********************************************************************** * File GMBIOB.C - Rel. 1.1 con uC/51 V. 1.10.09 * * GRIFO(R) via Dell'Artigiano 8/6 40016 S. Giorgio di Piano (BO) * * Tel. +39 051 892052 Fax. +39 051 893661 * * http://www.grifo.com http://www.grifo.it * * sales@grifo.it tech@grifo.it grifo@grifo.it * * by Angelini Gianluca del 04.07.03 * ********************************************************************** 04/07/03: GMBIOB.C - Rel. 1.1 - By Angelini Gianluca Questo Demo permette di utilizzare immediatamente le uscite bufferate a rele` disponibili su CN1 e gli ingressi optoisolati su CN6. Tramite la console si puo' settare lo stato dei quattro rele' di uscita oppure rappresentato lo stato degli 8 ingressi NPN/PNP. Inoltre vengono applicate le funzionalita' evolute offerte dal Mini Modulo, come ad esempio uscite comandate da segnali periodici automatici, ingressi contati via hw o che generano interrupt, ecc. N.B. Per evitare problemi non eseguire operazioni complesse su una singola riga, specialmente all'interno di procedure sui relativi parametri e/o variabili locali. */ /**************************************************************************** Header, costanti, strutture dati, ecc. ****************************************************************************/ #include "canary.h" #include #include #include #define FALSE 0x00 // Valori booleani #define TRUE 0xFF #define LF 0x0A // Codici ASCII #define CRET 0x0D // Variabili globali gestione I2C BUS near unsigned char risi2c; // Variabile errore I2C BUS bit unsigned char SDACAN @ 0xA1; // Pin SDA su CAN GMx=P2.1 bit unsigned char SCLCAN @ 0xA0; // Pin SCL su CAN GMx=P2.0 bit unsigned char SDA5115 @ 0xA0; // Pin SDA su GMM 5115=P2.0 bit unsigned char SCL5115 @ 0xA1; // Pin SCL su GMM 5115=P2.1 // Variabili globali gestione interrupt near unsigned int nint0,nint1; // Variabili globali usate dal main e dalle procedure near unsigned char minmod,scelta,dr,dw,hlp; near unsigned int val; inear unsigned char input[9]; // Buffer per input da console /**************************************************************************** Funzioni di utility generale e di gestione sezioni hw della scheda ****************************************************************************/ unsigned char divappr(unsigned long divid,unsigned long divis) /* Procedura di calcolo del quoziente intero a 8 bit, correttamente approssimato tra il dividendo ed il divisore passati nei parametri, con la tecnica delle sottrazioni sucessive. Si usa questa funzione per non avere i 2K di codice delle equivalenti funzioni di libreria. */ { unsigned char d; d=0; // Azzera quoziente while (divid>=divis) { divid=divid-divis; d++; } //endwhile divis=divis>>1; // Dimezza divisore per verifica resto if (divid>=divis) d++; //endif return d; } void init_cpu(void) /* Verifica la CPU montata sulla scheda e lo salva in apposita variabile. Effettua inoltre le apposite inizializzazioni: seriale, wait, ecc. */ { EA=0; // Assicura disabilitazione interrupt CKCON=0x00; // Setta X1 clock mode = standard mode AUXR=0x0C; // Seleziona ERAM su area dati esterna EECON=0x00; // Disabilita EEPROM del micro } void iniser(unsigned long baud) /* Inizializza la linea seriale con: Bit x chr = 8 Stop bit = 1 Parity = None Baud rate = baud usando come baud rate generator il timer 1. */ { SCON=0x052; // Modo 1, abilita ricevitore TMOD&=0x00F; // Timer 1 in modo auto-reload TMOD|=0x020; TR1=0; // Stop al TIMER 1 TH1=(unsigned char)(256-divappr((2*14745600),(384*baud))); // 14.7456 MHz PCON=PCON|0x080; // Setta SMOD=1 per baud rate alti TR1=1; // Start al TIMER 1 TI=1; // Setta bit fine trasmissione per console ottimizzata (SIOTYPE=k) } void clrscr(void) /* Effettua la funzione di clear screen per una generica console */ { unsigned char r; putc(CRET); for (r = 0 ; r < 25 ; r++) { putc(LF); // Trasmette 25 Line Feed } //endfor } void ritardo(unsigned int rit) /* Effettua un ritardo software di rit millisecondi, calibrato su un Clock di CPU da 14.7456 MHz, a seconda della CPU montata. */ { unsigned int r,rit1ms; rit1ms=100; // Valore sperimentale per ritardo di 1 msec. con 80c32 do { for (r=0 ; r0); } void setP1234inp(void) /* Setta tutte le linee di tutti i port (P1,P2,P3,P4) del modulo CAN GM1 in input. */ { ADCF=0x00; // Setta P1.x come port di I/O P1=0xFF; // Setta Port 1 in INPUT dr=P1; P2=0xFF; // Setta Port 2 in INPUT dr=P2; P3=0xFF; // Setta Port 3 in INPUT dr=P3; P4=0xFF; // Setta Port 4 in INPUT dr=P4; } void setoutbuf(unsigned char dato) /* Setta stato 4 linee di uscita bufferate con lo stato salvato nel nibble basso del parametro dato; il settaggio e` sui singoli bit del port 1 per evitare conflitti sulle altre linee usate in altre sezioni ed e` in logica PNP (ovvero un bit a 1 in dato setta a 0 la linea del micro e causa la chiusura del contatto d'uscita. */ { if ((dato&0x01)!=0) // Determina e setta stato P1.4=OUT A1 P1_4=0; else P1_4=1; //endif if ((dato&0x02)!=0) // Determina e setta stato P1.5=OUT A2 P1_5=0; else P1_5=1; //endif if ((dato&0x04)!=0) // Determina e setta stato P1.6=OUT A3 P1_6=0; else P1_6=1; //endif if ((dato&0x08)!=0) // Determina e setta stato P1.7=OUT A4 P1_7=0; else P1_7=1; //endif } unsigned char getinpbuf(void) /* Preleva lo stato delle 8 linee di ingresso bufferate restituendolo nel nome funzione. */ { unsigned char dato; dato=P3; // Preleva stato attuale dato=dato & 0xFC; // Maschera P3.1 e P3.0 if (P1_1!=0) // Acquisisce ed aggiunge stato P1.1 dato=dato | 0x01; if (P1_2!=0) // Acquisisce e salva stato P1.2 dato=dato | 0x02; return(dato); // Restituisce dato ottenuto } void riti2c(void) /* Genera ritardo per comunicazione sincrona in I2CBUS. Il ritardo e` sufficiente per un clock X 1, a 22 MHz. */ { #asm nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop #endasm } void starti2c(void) /* Genera sequenza di start per I2C BUS */ { if (minmod=='3') { SCL5115=0; // Genera sequenza di start con GMM 5115 SDA5115=1; riti2c(); SCL5115=1; SDA5115=0; riti2c(); SCL5115=0; } else { SCLCAN=0; // Genera sequenza di start con CAN GMx SDACAN=1; riti2c(); SCLCAN=1; SDACAN=0; riti2c(); SCLCAN=0; } //endif } void stopi2c(void) /* Genera sequenza di stop per I2C BUS */ { if (minmod=='3') { SCL5115=0; // Genera sequenza di stop con GMM 5115 SDA5115=0; riti2c(); SCL5115=1; SDA5115=1; riti2c(); SCL5115=0; } else { SCLCAN=0; // Genera sequenza di stop con CAN GMx SDACAN=0; riti2c(); SCLCAN=1; SDACAN=1; riti2c(); SCLCAN=0; } //endif } void wri2c_bit(unsigned char i2cbit) /* Serializza il bit D0 di i2cbit su I2C BUS */ { if (minmod=='3') { SCL5115=0; // Setta SDA e genera impulso positivo su SCL con GMM 5115 SDA5115=i2cbit; riti2c(); SCL5115=1; riti2c(); SCL5115=0; } else { SCLCAN=0; // Setta SDA e genera impulso positivo su SCL con CAN GMx SDACAN=i2cbit; riti2c(); SCLCAN=1; riti2c(); SCLCAN=0; } //endif } unsigned char rdi2c_bit(void) /* Deserializza un bit da I2C BUS e lo salva in D0 del risultato */ { unsigned char biti2c; if (minmod=='3') { SDA5115=1; // Evita conflitti su acquisizione SDA SCL5115=0; // Assicura stato SCL riti2c(); SCL5115=1; // Genera impulso positivo su SCL e su questo legge SDA biti2c=SDA5115; riti2c(); SCL5115=0; } else { SDACAN=1; // Evita conflitti su acquisizione SDA SCLCAN=0; // Assicura stato SCL riti2c(); SCLCAN=1; // Genera impulso positivo su SCL e su questo legge SDA biti2c=SDACAN; riti2c(); SCLCAN=0; } //endif return biti2c; } void wri2c_byte(unsigned char i2cbyte) /* Serializza il byte i2cbyte su I2C BUS */ { unsigned char b; for (b = 1; b <= 8; b++) { if ((i2cbyte & 0x80) == 0) // Determina e setta bit b wri2c_bit(0); else wri2c_bit(1); i2cbyte = i2cbyte << 1; } } unsigned char peekb(unsigned int addr) /* Legge il byte all'indirizzo addr dell'area dati esterna e lo restituisce nel nome funzione */ { return *(xdata unsigned char *)addr; // Preleva byte dalla locazione } void rd_ee(unsigned int eeaddr,unsigned char *eedato) /* Legge il byte eedato all'indirizzo eeaddr della EEPROM interna */ { AUXR=0x2E; // Deseleziona ERAM ed allunga durata MOVX EECON=0x02; // Seleziona EEPROM del micro su area dati esterna *eedato=peekb(eeaddr); // Effettua lettura EEPROM AUXR=0x0C; // Seleziona ERAM su area dati esterna EECON=0x00; // Disabilita EEPROM del micro } /**************************************************************************** Procedure risposta interrupt ****************************************************************************/ IRQ_VECTOR(ris_int0,IRQ_INT0); // Setta vettore /INT0 void ris_int0(void) interrupt { nint0++; // Procedura di risposta ad /INT0: incrementa contatore } IRQ_VECTOR(ris_int1,IRQ_INT1); // Setta vettore /INT1 void ris_int1(void) interrupt { nint1++; // Procedura di risposta ad /INT1: incrementa contatore } /**************************************************************************** Programma principale ****************************************************************************/ void main(void) { init_cpu(); // Inizializza tipo di CPU montata iniser(19200); // Inizializza seriale A di console con timer 1 setP1234inp(); // Setta Port 1,2,3,4 in INPUT clrscr(); // Seleziona mini modulo utilizzato puts("1->CAN GM1 , 2->CAN GM2 , 3->GMM 5115"); printf("Selezionare Mini Modulo montato su zoccolo ZC1 (1,2,3):"); do minmod=toupper(getc()); while ((minmod<'1') || (minmod>'3')); for(;;) // Loop infinito { clrscr(); // Presenta menu` programma test printf("Demo gestione I/O bufferati su GMB HR84 in uC/51 - Rel. 1.1 con "); switch (minmod) { case '1': puts("CAN GM1"); break; case '2': puts("CAN GM2"); break; case '3': puts("GMM 5115"); break; } // endswitch if (minmod=='3') // Ciclo di attesa scheda pronta { // Su GMM 5115 do rd_ee(0x07F8,&dr); while (dr!=0); } else { // Su CAN GM1, CAN GM2 do { dr=P2_1; starti2c(); wri2c_byte(0xA0); dw=rdi2c_bit(); } while ((dr==0) || (dw==1)); } // endif puts(""); puts("I->Ingressi optoisolati su CN6"); puts("U->Uscite a rele` su CN1"); printf("Sezione (I,U):"); do scelta=toupper(getc()); while ((scelta!='I') && (scelta!='U')); putc(scelta); if (scelta=='I') { dr=ADCF; // Setta P1.1 e P1.2 come port di I/O dw=dr & 0xF9; ADCF=dw; puts("Gestione 8 linee di ingresso optoisolate: collegare a CN6 segnali NPN o PNP"); puts("con relativo + o - su pin 9=COM."); puts("Acquisizione in corso, premere tasto per ultimare"); do { dr=getinpbuf(); // Legge e formatta stato degli opto in printf("%2X\r",dr); // Rappresenta stato acquisito ritardo(50); // Evita overflow sulla console } while(!kbhit()); getc(); puts("\n\rI segnali collegati a CN6 svolgono funzioni come interrupt, contatori, PCA"); puts("clock, ecc."); puts("Rappresentazione interrupt in corso, premere tasto per ultimare"); puts("IN 3 IN 4"); P3_2=1; // Setta P3.2=/INT0 in input P3_3=1; // Setta P3.3=/INT1 in input nint0=0; // Azzera contatori interrupt nint1=0; EX0=1; // Abilita EX0 per /INT0 IT0=1; // Seleziona fronte discesa EX1=1; // Abilita EX1 per /INT1 IT1=1; // Seleziona fronte discesa IPH0=0x05; // Setta priorita` massima (3) per /INT0 e IPL0=0x01; // priorita` medio alta (2) per /INT1 e IPH1=0x00; // priorita` minima (0) per i rimanenti interrupt IPL1=0x00; EA=1; // Abilita interrupt do { printf("%4X %4X\r",nint0,nint1); // Rappresenta contatori d'interrupt ritardo(50); // Evita overflow sulla console } while (! kbhit()); getc(); EA=0; // Disabilita interrupts EX0=0; EX1=0; puts("\n\rRappresenta contatore hardware. Premere tasto per ultimare"); puts("IN 5"); P3_4=1; // Setta P3.4=T0 in input TR0=0; // Disattiva Timer Counter 0 TL0=0x00; // Azzera valore attuale TH0=0x00; TMOD=(TMOD & 0xF0) | 0x05; // Setta Timer0=Counter a 16 bit (modo 1) TR0=1; // Attiva Timer Counter 0 do { val=(TH0 << 8) | TL0; // Acquisisce Timer Counter 0 printf("%4X\r",val); // Rappresenta combinazione letta } while (! kbhit()); getc(); TR0=0; // Disattiva Timer Counter 0 } else { dr=ADCF; // Setta P1.4..P1.7 come port di I/O dw=dr & 0x0F; ADCF=dw; clrscr(); puts("Gestione 4 linee di uscita a rele`: su CN1 i contatti A1,A2,B1,B2 sono"); puts("N.A. e vengono collegati al relativo comune A,B quando settati via software."); do { printf("\rCombinazione linee (0 per terminare):"); inputse(input, 8); // Preleva unsigned char dw=(unsigned char)atoi(input); setoutbuf(dw); // Formatta e setta stato delle uscite a rele` } while (dw!=0); puts("\n\rI segnali collegati a CN1 svolgono funzioni PCA (temporizzazioni, generazione"); puts("PWM,ecc)."); puts("L'uscita A1 si attiva a circa 1 Hz e duty cicle del 50%; premere un tasto per"); puts("ultimare."); P1_4=1; // Setta P1.4=OUT A1 alto per consentire settaggio del PCA TR0=0; // Disattiva Timer Counter 0 TL0=0x00; // Azzera valore attuale TH0=0x00; TMOD=TMOD & 0xF0; // Setta timer 0 come Timer a 13 bit (modo 0) TR0=1; // Attiva Timer Counter 0 CMOD=0x04; // Run in idle, Tmr 0 ovr, no interrupt CCON=0x40; // Abilita PCA timer/counter CCAPM1=0x42; // Abilita PWM su modulo 1 PCA con duty cycle = 50% CCAP1H=0x80; while (! kbhit()); getc(); TR0=0; // Disattiva Timer Counter 0 CCON=0x00; // Disabilita PCA timer/counter CCAPM1=0x00; // Disabilita PWM su modulo 1 PCA } // endif } //endfor (;;) // Fine loop infinito }