/* ********************************************************************** * File GMBAD.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: GMBAD.C - Rel. 1.1 - By Angelini Gianluca Una volta scelto il Mini Modulo, se la linea di ingresso analogico su CN4 e' disponibile, questo demo offre due operativita': calibrazione o acquisizione. La prima calcola un coefficiente di calibrazione grazie ad un segnale di riferimento esterno fornito dall'utente, e lo salva nella EEPROM interna del Mini Modulo. La seconda preleva il coefficiente di calibrazione dalla EEPROM, acquisice e rappresenta di continuo sulla console la combinazione dell'ingresso analogico, sia calibrato che non calibrato. Il demo puo' essere usato indifferentemente con range 0..2,5 V e 0..10 V. 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 TOUTEEP 5000 // Costante di time out gestione EEPROM // 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 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 nondisp(void) /* Rappresenta messaggio di risorsa non disponibile sul Mini Modulo scelto ed entra in un loop infinito */ { printf("Risorsa mancante su Mini Modulo. "); 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); } 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 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; } } void pokeb(unsigned int addr, unsigned char dato) /* Scrive il byte dato all'indirizzo addr dell'area dati esterna */ { *(xdata unsigned char *)addr=dato; // Salva byte nella locazione } 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 } unsigned char wr_ee(unsigned int eeaddr,unsigned char eedato) /* Scrive il byte eedato all'indirizzo eeaddr della EEPROM interna e restituisce flag booleano che indica il risultato dell'operazione: 0=corretta,1=errata. */ { unsigned int toee; AUXR=0x2E; // Deseleziona ERAM ed allunga durata MOVX EECON=0x02; // Seleziona EEPROM del micro su area dati esterna pokeb(eeaddr,eedato); // Setta dato nel column latch della EEPROM EECON=0x52; // Sequenza di programmazione EEPROM EECON=0xA2; toee=0; // Inizializza contatore timeout programmazione while ((EECON & 0x01) && (toee0) && (toeeCAN 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')); clrscr(); // Presenta programma demo printf("Demo gestione A/D converter della 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 for(;;) // Loop infinito { if (minmod=='1') { puts(""); puts("La sezione d'ingresso analogica e` basata su componenti con tolleranze."); puts("Per compensarle e` preferibile acquisire l'ingresso analogico tramite una"); puts("calibrazione software."); printf("Acquisizione,Calibrazione:"); do scelta=toupper(getc()); while ((scelta!='A') && (scelta!='C')); printf("%c\r\n",scelta); // Rappresenta scelta valida ADCF=0x01; // Setta P1.0 come ingresso A/D ADCLK=0x10; // Setta clock A/D if (scelta=='C') { // Gestione modalita` calibrazione puts("Collegare al pin 8 di CN4 un segnale analogico di riferimento vicino al"); printf("fondo scala scelto ed inserire la sua tensione, in mV (0-10000): "); inputse(input, 8); // Preleva unsigned int kcal=(unsigned int)atoi(input); // Preleva e salva tensione teorica kcmb=kcal; // per sucessive elaborazioni kcmb=(unsigned long) kcal*1023; // Determina combinazione teorica if (kcal>2500) kcmb=kcmb/10000; else kcmb=kcmb/2500; // endif cmb=0; // Determina combinazione reale for (hlp=1;hlp<=64;hlp++) // Effettua 64 conversioni cmb=cmb+adconv(0); // Aggiunge conversione ingresso 0 // endfor cmb=cmb>>6; // Ottiene media delle 64 combinazioni kcmb=kcmb*10000; // Ottiene coef. calibrazione a 4 cifre decimali kcmb=kcmb/cmb; kcal=(unsigned int)kcmb; printf("\r\nCoef. cal. ottenuto e salvato=%d\r\n",kcal); wr_ee(0x07F9,(uchar)(kcal&0xFF)); // Salva coef. calibrazione in EE wr_ee(0x07FA,(unsigned char)(kcal>>8)); } else { // Gestione modalita` acquisizione rd_ee(0x07F9,&dr); // Preleva coef. calibrazione da EEPROM rd_ee(0x07FA,&dw); kcal=(dw<<8)|dr; // Ottiene coef. calibrazione printf("Coef. cal. prelevato=%d\r\n",kcal); puts("Collegare a pin 8 di CN4 un segnale analogico compreso nel range scelto con"); puts("J6 e verificare le sottostanti combinazioni. Premere tasto per ultimare"); puts("CH0 acquisito,calibrato"); do { putc(CRET); cmb=adconv(0); // Converte ingresso 0 printf(" %4d",cmb); // Rappresenta combinazione acquisita kcmb=(unsigned long) cmb*kcal; // Determina combinazione calibrata cmb=(unsigned int)(kcmb/10000); printf(" %4d",cmb); // Rappresenta comb. calibrata ritardo(300); // Evita overflow sulla console e consente lettura } while (! kbhit()); getc(); putc(LF); } // endif } else nondisp(); // Risorsa non disponibile su Mini Modulo scelto // endif } //endfor (;;) // Fine loop infinito }