/* ********************************************************************** * File: GMBDA.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: GMBDA.C - Rel. 1.1 - By Graziano Gaiba Il demo utilizza la sezione 0 del PCA del Mini Modulo per generare (su CN7), 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 SDA @ 0xA1; // Pin SDA bit unsigned char SCL @ 0xA0; // Pin SCL // Variabili globali usate dal main e dalle procedure near unsigned char 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 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 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 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) { init_cpu(); // Inizializza tipo di CPU montata iniser(19200); // Inizializza seriale A di console con timer 1 setP01234inp(); // Setta Port 1,2,3,4 in INPUT clrscr(); // Seleziona mini modulo utilizzato puts("Demo D/A converter con PWM 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 e' in RS 422 o 485, il pin 6 di CN4 puo' essere"); puts("usato per la direzione della comunicazione, in tal caso il PWM non e'"); puts("disponibile. Continuare solo se J10 NON E' in 2-3."); printf("Continuare (S/N)? "); do { dr=toupper(getc()); } while(dr!='S' && dr!='N'); putc(dr); if(dr=='N') { puts("\nDIR non utilizzabile"); for(;;) ; } puts("\n"); puts("Pin 6 di CN7 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."); puts("Se J11 e' in 3-4, anche il rele' su D2 riceve il segnale."); dr=ADCF; // Setta P1.3 (collegato a pin 6 CN7) 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 }