/* ********************************************************************** * File GMBSER.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: GMBSER.C - Rel. 1.1 - By Angelini Gianluca Il demo e' un semplice esempio di comunicazione in grado di operare con tutti i protocolli elettrici disponibili su CN2 (RS 232, RS 422, RS 485, current loop o TTL). In dettaglio, tramite funzioni a basso livello, e' possibile programmare il baud rate da console, poi ogni carattere ricevuto dalla seriale viene ritrasmesso sulla stessa; la ricezione del carattere 'R' determina la gestione della direzione (segnale DIR) per RS 422 e RS 485. 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 // 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 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 putcar(unsigned char tra) /* Trasmette un carattere sulla seriale */ { while (!TI) // Atende trasmettitore libero continue; TI = 0; // Trasmette carattere SBUF = tra; } unsigned char getcar(unsigned char *ric) /* Testa se la linea seriale ha ricevuto un chr ed in caso affermativo lo restituisce nel parametro ric. */ { if (RI) { RI = 0; // Preleva e restituisce chr ricevuto *ric = SBUF; return(TRUE); } else return(FALSE); // Nessun chr disponibile //endif } 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 long baud; // Variabili per demo seriale 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 comunicazione seriale 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("Configurare linea seriale per protocollo elettrico desiderato seguendo le"); puts("indicazioni del manuale e collegare i segnali su CN2."); puts("Il demo verifica la ricezione di chr e quando disponibili li ritrasmette,"); puts("tramite funzioni a basso livello, fino alla ricezione del chr F con cui si"); puts("ripristinata la comunicazione con la console a 19200 Baud. La ricezione del"); puts("carattere R complementa lo stato del segnale DIR usato nella comunicazione"); puts("RS422,RS485 per gestire il trasmettitore."); printf("Baud Rate="); inputse(input, 8); // Preleva unsigned long baud=(unsigned long)atol(input); puts(""); ritardo(10); // Attende fine trasmissione ultimo chr iniser(baud); // Inizializza linea seriale con baud rate inserito dr=0; do { if (getcar(&dr)) // Se chr ricevuto da seriale { if (dr=='R') { // Complementa stato trasmettitore if (minmod=='1') P2_3=P2_3 ^ 1; // Tramite segnale DIR=MM PIN 11 else P1_3=P1_3 ^ 1; // Tramite segnale DIR=MM PIN 24 // endif } // endif putcar(dr); // Trasmette chr ricevuto } // endif } while (dr!='F'); // Attende ricezione F ritardo(10); // Attende fine trasmissione ultimo chr iniser(19200); // Inizializza seriale per console a 19200 Baud } //endfor (;;) // Fine loop infinito }