/* ********************************************************************** * File GMBDA.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: GMBDA.C - Rel. 1.1 - By Angelini Gianluca Il demo utilizza la sezione 0 del PCA del Mini Modulo per generare (su CN4), un segnale PWM di frequenza prestabilita, con duty cycle settabile in percentuale da console. Tale segnale, collegato ad una opportuna circuiteria integratrice (rete RC, amplificatore operazionale con capacita' su ramo di retroazione, ecc.) permette di ottenere un segnale analogico paragonabile a quello di un D/A. L'esecuzione del demo e' subordinata al Mini Modulo utilizzato e alla configurazione della linea seriale. 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; } } 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 dall a 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) { 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')); clrscr(); // Presenta menu` programma test printf("Demo D/A converter con PWM 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("Pin 6 di CN4 genera un segnale PWM con cui generare un segnale analogico."); puts("Il demo setta una frequenza=4800Hz e richiede un duty cyle ad 8 bit."); dr=ADCF; // Setta P1.3 (collegato a pin 6 CN4) come port di I/O dw=dr & 0xF7; ADCF=dw; P1_3=1; // A livello alto per consentire settaggio da parte del PCA CMOD=0x00; // Run in idle, Fpca/6, no interrupt CCON=0x40; // Abilita PCA timer/counter dw=0; // Per non uscire subito ed azzerare PCA for(;;) // Loop infinito { val=dw*255; // Calcola duty cycle a 8 bit da percentuale val=val/100; dw=(unsigned char)val; CCAPM0=0x42; // Abilita PWM su modulo 0 PCA CCAP0H=dw; // Programma duty cycle per PWM 0 printf("\rDuty Cycle (0..100%):"); inputse(input, 8); // Preleva unsigned char dw=(unsigned char)atoi(input); } //endfor (;;) // Fine loop infinito CCON=0x00; // Disabilita PCA timer/counter CCAPM0=0x00; // Disabilita PWM su modulo 0 PCA }