/* ********************************************************************** * File: GMBTMP.C - Rel. 1.1 con uC/51 V. 1.20.04 * * Schede: GMB HR168 con GMM AC Zero * * 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 * * by Graziano Gaiba del 07.06.05 * ********************************************************************** 07/06/05: GMBTMP.C - Rel. 1.1 - By Graziano Gaiba Se sulla GMB HR168 e' disponibile il Real Time Clock, questo demo permette di gestire tre temporizzatori che agiscono sulle uscite bufferate di CN3 e CN4. In dettaglio da console per tutti i temporizzatori si puo` stabilire l'attivazione e l'intervallo di tempo in secondi, mentre solo per i primi due e` inseribile la combinazione d'uscita; il terzo invece disattiva tutte le uscite. 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 #define FALSE 0x00 // Valori booleani #define TRUE 0xFF #define LF 0x0A // Codici ASCII #define CRET 0x0D #define RTCSLA 0xA0 // Slave address RTC PCF 8583 // Variabili globali gestione I2C BUS near unsigned char risi2c; // Variabile errore I2C BUS bit unsigned char SDA @ 0xA1; // Pin SDA bit unsigned char SCL @ 0xA0; // Pin SCL // 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 waitkey(void) /* Rappresenta messaggio ed attende pressione tasto */ { printf("Premere tasto per continuare.."); getc(); puts(""); } void nondisp(void) /* Rappresenta messaggio di risorsa non disponibile sulla GMB HR168 */ { printf("\nReal Time Clock opzionale non presente. "); for(;;); } 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); } unsigned char bintobcd(unsigned char d) /* Procedura di trasformazione di un byte in codifica binaria (0-99) nella corrispondente codifica bcd. */ { d=((d/10)<<4)|(d%10); return d; } unsigned char bcdtobin(unsigned char d) /* Procedura di trasformazione di un byte in codifica bcd nella corrispondente codifica binaria (0-99). */ { d=((d>>4)*10)+(d&0x0F); return d; } void setP01234inp(void) /* Setta tutte le linee di tutti i port (P1,P2,P3,P4) del modulo CAN GM1 in input. */ { P0=0xFF; // Setta Port 0 in INPUT dr=P0; 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 8 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 B1 P1_6=0; else P1_6=1; //endif if ((dato&0x08)!=0) // Determina e setta stato P1.7=OUT B2 P1_7=0; else P1_7=1; //endif if ((dato&0x10)!=0) // Determina e setta stato P4.0=OUT C1 P4_0=0; else P4_0=1; //endif if ((dato&0x20)!=0) // Determina e setta stato P4.1=OUT C2 P4_1=0; else P4_1=1; //endif if ((dato&0x40)!=0) // Determina e setta stato P2.2=OUT D1 P2_2=0; else P2_2=1; //endif if ((dato&0x80)!=0) // Determina e setta stato P1.3=OUT D2 P1_3=0; else P1_3=1; //endif } 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 */ { SCL=0; // Genera sequenza di start SDA=1; riti2c(); SCL=1; SDA=0; riti2c(); SCL=0; } void stopi2c(void) /* Genera sequenza di stop per I2C BUS */ { SCL=0; // Genera sequenza di stop SDA=0; riti2c(); SCL=1; SDA=1; riti2c(); SCL=0; } void wri2c_bit(unsigned char i2cbit) /* Serializza il bit D0 di i2cbit su I2C BUS */ { SCL=0; // Setta SDA e genera impulso positivo su SCL SDA=i2cbit; riti2c(); SCL=1; riti2c(); SCL=0; } unsigned char rdi2c_bit(void) /* Deserializza un bit da I2C BUS e lo salva in D0 del risultato */ { unsigned char biti2c; SDA=1; // Evita conflitti su acquisizione SDA SCL=0; // Assicura stato SCL riti2c(); SCL=1; // Genera impulso positivo su SCL e su questo legge SDA biti2c=SDA; riti2c(); SCL=0; 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 rdi2c_byte(void) /* Deserializza un byte da I2C BUS e lo salva nel risultato */ { unsigned char b,tmp; tmp = 0; for (b = 1; b <= 8; b++) { tmp = tmp << 1; tmp = tmp | rdi2c_bit(); // Preleva e salva bit b } return tmp; } unsigned char wr_i2c(unsigned char i2csla,unsigned char i2cadd,unsigned char i2cdat) /* Scrive il byte i2cdat all'indirizzo i2caddr del dispositivo I2C BUS che ha uno slave address i2csla. Restituisce flag booleano che indica il risultato dell'operazione: 0=corretta,1=errata. */ { unsigned char i2cris; i2cris = 0; // Setta risultato corretto starti2c(); // Fornisce sequenza di start wri2c_byte(i2csla); // Fornisce slave address+W i2cris = i2cris | rdi2c_bit(); // Controlla ACK su slave address+W wri2c_byte(i2cadd); // Fornisce address i2cris = i2cris | rdi2c_bit(); // Controlla ACK su address wri2c_byte(i2cdat); // Fornisce dato i2cris = i2cris | rdi2c_bit(); // Controlla ACK su dato stopi2c(); // Fornisce sequenza di stop return i2cris; // Restituisce risultato operazione } unsigned char rd_i2c(unsigned char i2csla,unsigned char i2cadd,unsigned char *i2cdat) /* Legge il byte i2cdat dall'indirizzo i2caddr del dispositivo I2C BUS che ha uno slave address i2csla. Restituisce flag booleano che indica il risultato dell'operazione: 0=corretta,1=errata. */ { unsigned char i2cris; i2cris = 0; // Setta risultato corretto starti2c(); // Fornisce sequenza di start wri2c_byte(i2csla); // Fornisce slave address+W i2cris = i2cris | rdi2c_bit(); // Controlla ACK su slave address+W wri2c_byte(i2cadd); // Fornisce address i2cris = i2cris | rdi2c_bit(); // Controlla ACK su address starti2c(); // Fornisce sequenza di start wri2c_byte(i2csla | 0x01); // Fornisce slave address+R i2cris = i2cris | rdi2c_bit(); // Controlla ACK su slave address+R *i2cdat = rdi2c_byte(); // Preleva dato stopi2c(); // Fornisce sequenza di stop return i2cris; // Restituisce risultato operazione } void getrtc(unsigned char *set,unsigned char *ann,unsigned char *mes,unsigned char *gio,unsigned char *ore,unsigned char *min,unsigned char *sec) /* Preleva data ed ora attuale dal RTC della CAN GM1 e le restituisce nei parametri della funzione */ { risi2c=rd_i2c(RTCSLA,0x02,&dr); // Legge e determina secondi *sec=bcdtobin(dr); risi2c=rd_i2c(RTCSLA,0x03,&dr); // Legge e detrmina minuti *min=bcdtobin(dr); risi2c=rd_i2c(RTCSLA,0x04,&dr); // Legge e determina ore *ore=bcdtobin(dr); risi2c=rd_i2c(RTCSLA,0x05,&dr); // Legge e determina giorno,anno *gio=bcdtobin(dr&0x3F); *ann=(dr&0xC0)>>6; risi2c=rd_i2c(RTCSLA,0x06,&dr);// Legge e determina giorno settimana e mese *set=(dr&0xE0)>>5; *mes=bcdtobin(dr&0x1F); } void setrtc(unsigned char set,unsigned char ann,unsigned char mes,unsigned char gio,unsigned char ore,unsigned char min,unsigned char sec) /* Setta RTC della CAN GM1 con i dati passati nei parametri, nel formato a 24 ore ed abilita interrupt ogni secondo. */ { risi2c=wr_i2c(RTCSLA,0x00,0x84); // Setta stop risi2c=wr_i2c(RTCSLA,0x01,0x00); // Setta centinaia di secondi risi2c=wr_i2c(RTCSLA,0x02,bintobcd(sec)); // Setta secondi risi2c=wr_i2c(RTCSLA,0x03,bintobcd(min)); // Setta minuti risi2c=wr_i2c(RTCSLA,0x04,bintobcd(ore)); // Setta ORE,formato 24h risi2c=wr_i2c(RTCSLA,0x05,(bintobcd(gio)|(ann<<6))); // Setta giorno e anno risi2c=wr_i2c(RTCSLA,0x06,(bintobcd(mes)|(set<<5)));// Setta mese,settimana risi2c=wr_i2c(RTCSLA,0x07,0x00); // Setta timer risi2c=wr_i2c(RTCSLA,0x00,0x00); // Setta start } 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 } /**************************************************************************** Programma principale ****************************************************************************/ void main(void) { unsigned char set,gio,mes,ann,ore,min,sec; // Variabili per RTC unsigned char t[3],o[3]; // Variabili per temporizzatori init_cpu(); // Inizializza tipo di CPU montata iniser(19200); // Inizializza seriale A di console con timer 1 setP01234inp(); // Setta Port 0,1,2,3,4 in INPUT clrscr(); // Presenta menu` programma test puts("Demo gestione temporizzatori su GMB HR168 in uC/51 - Rel. 1.1 con GMM AC Zero"); do // Ciclo di attesa scheda pronta { rd_ee(0x07F8,&dr); } while (dr!=0); puts("Se il modulo GMB HR168 non e' provvisto del Real Time Clock opzionale il"); puts("demo non puo' funzionare. Continuare solo se il Real Time Clock"); puts("opzionale e' installato."); printf("Continuare (S/N)? "); do { dr=toupper(getc()); } while(dr!='S' && dr!='N'); putc(dr); if(dr=='N') { nondisp(); } for(;;) // Loop infinito { puts(""); puts("Gestione 3 temporizzatori con precisione del secondo; per i primi 2 e`"); puts("definibile lo stato uscite su CN3 e CN4 mentre il terzo le disattiva."); for (dw=0;dw<3;dw++) { printf("\nTempo %d (1..255,0 disattiva)? ",dw); inputse(input, 8); // Preleva unsigned char t[dw]=(unsigned char)atoi(input); // Preleva e salva tempo settaggio if ((dw!=2) && (t[dw]!=0)) { printf("\nStato uscite (0..255)? "); inputse(input, 8); // Preleva unsigned char o[dw]=(unsigned char)atoi(input); // Preleva e salva stato uscite } // endif } // endfor o[2]=0; // Predispone azzeramento uscite per terzo temp. puts("\nSecondi trascorsi"); getrtc(&set,&ann,&mes,&gio,&ore,&min,&sec); // Preleva RTC dw=sec; // Inizializza secondi precedenti hlp=0; // Azzera contatore secondi trascorsi while ((t[0]+t[1]+t[2])!=0) // Se almeno un temporizzatore attivo { getrtc(&set,&ann,&mes,&gio,&ore,&min,&sec); // Preleva RTC if (sec!=dw) // Se secondi variati { hlp++; // Incrementa contatore secondi trascorsi printf("%3d\r",hlp); // Rappresenta secondi trascorsi for (dw=0;dw<3;dw++) // Gestisce 3 temporizzatori { if (hlp==t[dw]) { setoutbuf(o[dw]); t[dw]=0; } // endif } // endfor dw=sec; // Aggiorna secondi precedenti } // endif } // endwhile puts(""); // Attende tasto per uscire waitkey(); } // endfor (;;) // Fine l oop infinito }