/* ********************************************************************** * File GMBSER.C - Rel. 1.1 con uC/51 V. 1.20.04 * * GRIFO(R) via Dell'Artigiano 8/6 40016 S. Giorgio di Piano (BO) * * Schede: GMB HR 84 + GMM 936 * * Tel. +39 051 892052 Fax. +39 051 893661 * * http://www.grifo.com http://www.grifo.it * * by Graziano Gaiba del 06.06.05 * ********************************************************************** 06/06/05: GMBSER.C - Rel. 1.1 - By Graziano Gaiba 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 "89LPC936.h" #include #include #include #define FALSE 0x00 // Valori booleani #define TRUE 0xFF #define BEL 0x07 // Codici ascii #define LF 0x0A #define CRET 0x0D #define RCINT 7372800 // Frequenza clock da RC interno #define QZ11M 11059200 // Frequenza clock da quarzo esterno #define TOUTEEP 5000 // Costante di time out gestione EEPROM // Variabili globali usate dal main e dalle procedure near unsigned long clk; // Clock della CPU near unsigned long baud; near unsigned char i,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 rd_ucfg1(void) /* Legge il byte di configurazione UCFG1 in FLASH grazie alle procedure IAP del Boot Rom del P89LPC932. Restituisce byte letto nel nome funzione, senza controllare gli eventuali errori. */ { #asm mov A,#$03 ; Usa comando Misc. Read mov R7,#$00 ; Legge registro UCFG1 lcall $0FF03 ; Chiama procedura IAP ad indirizzo PGM_MTP #endasm } 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 } // Controllo correttezza periferiche interne con eventuali ritentativi // Usa le variabili generali st,t,m,ind,hlpw void check(void) { unsigned char st,s,t,m,ind; DEECON = 0x01; t = peekb(0xff); DEEADR = 0xFF; t = 1; ind = 0xF7; do { m = peekb(0x07); if(m & 0x80) { m = m & 0x03; ind = m + 0xF8; t = peekb(ind); } else { t = 0; } st = DEECON & 0x80; } while(st == 0); st = DEEDAT; do { s = peekb(ind++); if(ind == 0xFF) { ind = 0xF9; } do { m = s; if(! st) { t++; } } while(t <= m); } while(st != 0); } void init_cpu(void) /* Verifica la frequenza della CPU montata sulla scheda e lo salva in apposita variabile. Effettua inoltre le apposite inizializzazioni. */ { unsigned char M1, M2; EA=0; // Assicura disabilitazione interrupt P1M1 = 0; // Necessario per la seriale RS232 /* IN1 <- P0.0 IN2 <- P0.1 IN3 <- P0.2 IN4 <- P1.4 IN5 <- P0.3 IN6 <- P0.4 IN7 <- P0.5 IN8 <- P0.7 OUT A1 -> P1.6 OUT A2 -> P1.7 OUT B1 -> P2.1 OUT B2 -> P2.7 */ PT0AD = 0; // P0.1-5 come I/O non c. analogico M1 = P0M1; // Imposta P0.0-5 e P0.7 come solo input M2 = P0M2; M1 = M1 | 0xDF; M2 = M2 & 0x40; P0M1 = M1; P0M2 = M2; M1 = P1M1; // Imposta P1.4 come solo input e M2 = P1M2; // P1.6 e P1.7 come open drain output M1 = M1 | 0xD0; M2 = M2 | 0xC0; M2 = M2 & 0xEF; P1M1 = M1; P1M2 = M2; M1 = P2M1; // Imposta P2.1 e P2.7 come M2 = P2M2; // open drain output M1 = M1 | 0x82; M2 = M2 | 0x82; P2M1 = M1; P2M2 = M2; } void iniser(unsigned long baud, unsigned char stop) /* Inizializza la linea seriale con: Bit x chr = 8 Stop bit = stop Parity = None Baud rate = baud usando l'apposito baud rate generator interno al micro e la frequenza di clock salvata nella variabile globale clk. */ { unsigned long divbr; PCON = PCON & 0xBF; // Azzera bit SMOD0 x settare modo if (stop==1) SCON=0x52; // Modo 1 (1 stop),No multiproc,Attiva rx else SCON=0xDA; // Modo 3 (2 stop),No multiproc,Attiva rx //endif BRGCON=0x02; // Imposta baud rate passato divbr=baud << 4; // Calcola divisore per baud divbr=clk-divbr; divbr=divbr/baud; BRGR0=(unsigned char)(divbr & 0x00FF); divbr=divbr >> 8; BRGR1= (unsigned char)(divbr & 0x00FF); BRGCON=0x03; 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 ritardo(unsigned int rit) /* Effettua un ritardo software di rit millisecondi, con clock presente sul minimodulo, precedentemente determinato e salvato nella variabile globale clk. */ { unsigned int r,rit1ms; if (clk==RCINT) { rit1ms=335; // Valore sperimentale per ritardo di 1 msec a 7 MHz } else { rit1ms=500; // Valore sperimentale per ritardo di 1 msec a 11 MHz }; //endif do { for (r=0 ; r0); } 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 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. La corrispondenza tra port ed uscite a relé è: OUT A1 -> P1.6 OUT A2 -> P1.7 OUT B1 -> P2.1 OUT B2 -> P2.7 */ { if ((dato&0x01)!=0) // Determina e setta stato P1.6=OUT A1 P1_6=0; else P1_6=1; //endif if ((dato&0x02)!=0) // Determina e setta stato P1.7=OUT A2 P1_7=0; else P1_7=1; //endif if ((dato&0x04)!=0) // Determina e setta stato P2.1=OUT A3 P2_1=0; else P2_1=1; //endif if ((dato&0x08)!=0) // Determina e setta stato P2.7=OUT A4 P2_7=0; else P2_7=1; //endif } unsigned char getinpbuf(void) /* Preleva lo stato delle 8 linee di ingresso bufferate e lo restituisce. La corrispondenza tra port ed ingressi optoisolati NPN/PNP è: IN1 <- P0.0 IN2 <- P0.1 IN3 <- P0.2 IN4 <- P1.4 IN5 <- P0.3 IN6 <- P0.4 IN7 <- P0.5 IN8 <- P0.7 */ { // Preleva stato attuale e lo complementa perché gli ingressi funzionano // in logica complementata, poi restituisce dato il ottenuto. unsigned char statusP0, statusP1, val = 0; statusP0 = P0; statusP1 = P1; // Bits 0..2 di val val = (statusP0 & 0x07); // Bit 3 di val val |= (statusP1 & 0x10) >> 1; // Bits 4..6 di val val |= (statusP0 & 0x38) << 1; // Bit 7 di val val |= (statusP0 & 0x80); return(~val); } /**************************************************************************** Funzioni dimostrative della console a basso livello ****************************************************************************/ 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 } /**************************************************************************** Programma principale ****************************************************************************/ void main(void) { init_cpu(); // Inizializza sezioni necessarie della CPU clk=RCINT; // Setta clock per RC interno (puo` essere acquisito solo dopo) P0M1=P0M1 | 0x40; // Setta configurazione P0.6 in modo 3=Open Drain P0M2=P0M2 | 0x40; for (i=0 ; i<16 ; i++) // Ritardo partenza Hyperterminal con lampeggio DL1 { P0_6=!P0_6; // Complementa stato DL1 ritardo(125); } //endfor dr=rd_ucfg1(); // Preleva configurazione da FLASH dr=dr & 0x07; // Mantiene configurazione della sorgente di CLK switch (dr) { case 0x00: clk=QZ11M; // Frequenza clock da quarzo esterno break; case 0x03: clk=RCINT; // Frequenza clock da RC interno break; } iniser(19200, 1); // Inizializza seriale A di console for(;;) { clrscr(); // Pulsce lo schermo puts("Demo 1.1 per GMM936 ds300803+GMBHR84 ds220503"); // Controllo interno check(); 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(""); printf("Stop Bit="); inputse(input, 8); // Preleva unsigned char dw=(uchar)atoi(input); puts(""); ritardo(10); // Attende fine trasmissione ultimo chr iniser(baud, dw); // Inizializza linea seriale con baud rate inserito dr=0; // Pone in output (push pull) P2.0 P2M1 &= 0xFE; P2M2 |= 0x01; do { if (getcar(&dr)) // Se chr ricevuto da seriale { if (dr=='R') { // Complementa stato trasmettitore P2_0 = P2_0 ^ 1; // Tramite segnale DIR=MM PIN 11 } // endif putcar(dr); // Trasmette chr ricevuto } // endif } while (dr!='F'); // Attende ricezione F ritardo(10); // Attende fine trasmissione ultimo chr iniser(19200, 1); // Inizializza seriale per console a 19200 Baud, 1 Bit stop } //endfor (;;) // Fine loop infinito }