/* ********************************************************************** ** Program: Da_e.c - Version : 1.4 - 03 October 2003 ** ** Compiler: uC/51 Ver. 1.10.10 ** ** Board: K51-AVR and ATMEL AT89c4051 ** ** Firm: grifo(r) ITALIAN TECHNOLOGY ** ** Via Dell' Artigiano 8/6 40016 San Giorgio di Piano (BO) ** ** Tel.+39 051 892 052 Fax +39 051 893 661 ** ** http://www.grifo.com http://www.grifo.it ** ** sales@grifo.it tech@grifo.it grifo@grifo.it ** ** ** ** Written by: Graziano Gaiba ** ********************************************************************** This demo allows to drive an I2C BUS peripheral on board of K51-AVR, PCF8591. PCF 8591 is provided with one analog output for D/A conversions with 8 bits resolution, all the operations of activation are performed through synchronous serial interface I2C BUS. This demo allows to set the voltage output level through PC keyboard, and writes 'da' on the 7 segments display of K51-AVR to indicate that demo is running. 05.06.2000 by Adriano Pedrielli (for K51 alone) (Original version in BASCOM 8051) 03.10.2003 by Graziano Gaiba Translation in uC/51. */ #include #include #include #define FALSE 0x00 // Values boolean #define TRUE 0xFF #define LF 0x0A #define CRET 0x0D /***************** Addresses list for Saa1064 ***********************/ #define Saa1064 0x38 // Slave address SAA1064 #define Wsaa1064 0x70 // Slave address SAA1064 in Write #define Rsaa1064 0x71 // Slave address SAA1064 in Read #define Ctb 0x00 // Ind. Control byte #define Dig1 0x01 // Ind. Digit 1 #define Dig2 0x02 // Ind. Digit 2 #define Dig3 0x03 // Ind. Digit 3 #define Dig4 0x04 // Ind. Digit 4 /***************** Addresses list for PCF8591 ***********************/ #define Pcf8591 0x48 // Slave address PCF8591 #define Wpcf8591 0x90 // Slave address PCF8591 in Write #define Rpcf8591 0x91 // Slave address PCF8591 in Read // Inizialization od SAA1064 #define saa1064_init_length 0x06 // Inizialization sequence length const unsigned char saa1064_init[]={ Ctb, // Points control register 0x27, // = 0b00100111 // bit0 =1 dynamic mode // bit1 =1 digit 1+3 not blanked // bit2 =1 digit 2+4 not blanked // bit3 =0 no test segment // bit4 =0 no 3mA segment current // bit5 =1 6mA segment current // bit6 =0 no 12mA segment current // bit7 =0 indifferent 94, // writes 'd' 119, // writes 'a' 0, // writes DY3 off 0 // writes DY4 off }; // Codes to convert a figure from 0 to F in 7 segments coding const unsigned char cifra_7seg[]={0x3F,0x06,0x5B,0x4F,0x66, 0x6D,0x7D,0x07,0x7F,0x6F, 0x77,0x7C,0x39,0x5E,0x79,0x71}; // I2C BUS management globals bit unsigned char SDA @ 0x97; // Pin SDA=P1.7 bit unsigned char SCL @ 0x96; // Pin SCL=P1.6 /********* General utilities and hardware section management ***********/ void iniser(unsigned long baud) /* Initialize serial line with: Bit x chr = 8 Stop bit = 1 Parity = None Baud rate = baud using timer 1 as baud rate generator. */ { SCON=0x052; // Mode 1, enable receiver TMOD&=0x00F; // Timer 1 in auto-reload TMOD|=0x020; TR1=0; // Stop TIMER 1 TH1=256-((2*11059200)/(384*baud)); // baud 14.7456 MHz PCON=PCON|0x080; // SetSMOD=1 for higher baud rates TR1=1; // Start TIMER 1 } void clrscr(void) /* Clear the screen of a generic console */ { unsigned char r; putc(CRET); for (r = 0 ; r < 25 ; r++) { putc(LF); // Sends 25 Line Feed } //endfor } void waitkey(void) /* Shows a message and waits for a key pressed */ { printf("hit a key to continue.."); getc(); puts(""); } void ritardo(unsigned int rit) /* Performs a software delay of rit milliseconds, calibrated on a CPU Clock 11 MHz. */ { unsigned int r,rit1ms; rit1ms=100; // Sperimental value for delay of 1 msec. with 80c32 do { for (r=0 ; r0); } void riti2c(void) /* Delay for I2CBUS synchronous communication. */ { #asm nop nop nop nop nop nop nop nop nop nop nop nop nop nop nop #endasm } void starti2c(void) /* Start sequence for I2C BUS */ { SCL = 0; // Start sequence SDA = 1; riti2c(); SCL = 1; SDA = 0; riti2c(); SCL = 0; } void stopi2c(void) /* Stop sequence for I2C BUS */ { SCL = 0; // Stop sequence SDA = 0; riti2c(); SCL = 1; SDA = 1; riti2c(); SCL = 0; } void wri2c_bit(unsigned char i2cbit) /* Serializes bit D0 of i2cbit on I2C BUS */ { SCL = 0; // Set SDA and generates positive impulse on SCL SDA = i2cbit; riti2c(); SCL = 1; riti2c(); SCL = 0; } unsigned char rdi2c_bit(void) /* Deserializes a bit from I2C BUS and stores it in D0 of returned value*/ { unsigned char biti2c; SDA = 1; // Prevents conflicts on SDA acquisition SCL = 0; // Assures status of SCL riti2c(); SCL = 1; // Generates positive impulse on SCL and reads SDA biti2c = SDA; riti2c(); SCL = 0; return biti2c; } void wri2c_byte(unsigned char i2cbyte) /* Serializes byte i2cbyte to I2C BUS */ { unsigned char b; for (b = 1; b <= 8; b++) { if ((i2cbyte & 0x80) == 0) // Test and set bit b wri2c_bit(0); else wri2c_bit(1); i2cbyte = i2cbyte << 1; } } unsigned char rdi2c_byte(void) /* Deserializes byte from I2C BUS and stores it in returned value */ { unsigned char b,tmp; tmp = 0; for (b = 1; b <= 8; b++) { tmp = tmp << 1; tmp = tmp | rdi2c_bit(); // Reads and stores bit b } return tmp; } unsigned char wr_i2c(unsigned char i2csla,unsigned char i2cadd,unsigned char i2cdat) /* Writes byte i2cdat to address i2caddr of I2C BUS device with slave address in i2csla. Returns boolean flag indicating result of operation: 0=OK,1=error. */ { unsigned char i2cris; i2cris = 0; // Set OK as result starti2c(); // Start sequence wri2c_byte(i2csla); // Slave address+W i2cris = i2cris | rdi2c_bit(); // Check ACK on slave address+W wri2c_byte(i2cadd); // Address i2cris = i2cris | rdi2c_bit(); // Check ACK on address wri2c_byte(i2cdat); // Data i2cris = i2cris | rdi2c_bit(); // Check ACK on data stopi2c(); // Stop sequence return i2cris; // Result of operation } unsigned char rd_i2c(unsigned char i2csla,unsigned char i2cadd,unsigned char *i2cdat) /* Reads byte and returns it as result from address i2caddr of I2C BUS device with slave address in i2csla. Returns boolean flag indicating result of operation: 0=OK,1=error. */ { unsigned char i2cris; i2cris = 0; // Set OK as result starti2c(); // Start sequence wri2c_byte(i2csla); // Slave address+W i2cris = i2cris | rdi2c_bit(); // Check ACK on slave address+W wri2c_byte(i2cadd); // Address i2cris = i2cris | rdi2c_bit(); // Check ACK on address starti2c(); // Start sequence wri2c_byte(i2csla | 0x01); // Slave address+R i2cris = i2cris | rdi2c_bit(); // Check ACK on slave address+R *i2cdat = rdi2c_byte(); // Reads data stopi2c(); // Stop sequence return i2cris; // Result of operation } // Send to indicated slave address (as first parameter) number of bytes indicated // (as third parameter) stored from address indicated (as second parameter). // If number of bytes is 0, it does nothing. // Returns boolean flag indicating result of operation: // 0=OK,1=error. unsigned char i2c_invia(unsigned char slave, unsigned char *dati, unsigned char ndati) { unsigned char i2cris, i; if(! ndati) // If ndati is zero, exits return 0; i2cris=0; starti2c(); // Start sequence wri2c_byte(slave); // Slave address+W i2cris|=rdi2c_bit(); // Check ACK on slave address+W i=0; while(ndati--) // Send ndati bytes { wri2c_byte(dati[i++]); i2cris|=rdi2c_bit(); // Check ACK } stopi2c(); // Stop sequence return i2cris; // Return result } // Send to indicated slave address (as first parameter) number of bytes indicated // (as third parameter) stored from address indicated (as second parameter),then // expects to receive as answer indicated number of bytes (fourth parameter) and // stores them starting from address previously specified in second parameter. // Returns boolean flag indicating result of operation: // 0=OK,1=error. unsigned char i2c_ricevi(unsigned char slave, unsigned char *dati, unsigned char ndati_out, unsigned char ndati_in) { unsigned char i2cris, i; if((! ndati_in) && (! ndati_out)) // Se ndati_in e ndati_out sono zero,esce return 0; i2cris=0; // Invia i dati starti2c(); // Start sequencet wri2c_byte(slave); // Slave address+W i2cris|=rdi2c_bit(); // Check ACK on slave address+W i=0; while(ndati_out--) // Send ndati_out bytes { wri2c_byte(dati[i++]); // Send data i2cris|=rdi2c_bit(); // Check ACK } // Riceve i dati starti2c(); wri2c_byte(slave | 0x01); // Slave address+W i2cris|=rdi2c_bit(); // Check ACK on slave address+R i=0; while(ndati_in--) // Reads ndati_in bytes { dati[i++]=rdi2c_byte(); // Get data if(ndati_in) { wri2c_bit(0); // Send ACK } else { wri2c_bit(1); // Last data read, send NACK } } stopi2c(); // Stop sequence return i2cris; // Return the result } void demo_init(void) { unsigned char i; // Wait SAA1064 to turn on do { starti2c(); wri2c_byte(Rsaa1064); rdi2c_bit(); i = rdi2c_byte(); wri2c_byte(1); // Not Acknowledge stopi2c(); } while(i); // Send SAA1064 initialization se quence i2c_invia(Wsaa1064, saa1064_init, saa1064_init_length); } /******************** D/A converter management **************************** This procedure allows to set an output value on the D/A converter, available on IC2 (PCF8591). Parameters: Input : value from 0 to 255 (0v ..+Vref) Output : nothing ************************************************************************/ void dac(unsigned char v) // D/A converter management { // Slave address and D/A activation command wr_i2c(Wpcf8591, 0x40, v); } // Converts a value from 0 to 255 in two 4 bit hexadecimal figures void cifre(unsigned char v, unsigned char *c1, unsigned char *c2) { *c1=(v & 0xf0) >> 4; *c2=v & 0x0f; } /******** Converts a figure in range from 0 to F in 7 segments ******** This procedure converts a figure in range from 0 to F in 7 segments format, if value is greater than F the display is off. Parameters: Input : value in the range from 0 to F Outout : value in 7 segments format. ************************************************************************/ unsigned char digit(unsigned char n) { if(n < 16) { return cifra_7seg[n]; // reads value from table } else { return 0; // If value greater than 15 turn off display } } /*********************** Visualizes a byte in HEX ********************* The first display visualizes the number of the channel being converted, the second display is off. This procedure allows to show a byte in hexadecimal format in the two displays on the right. E.g.: 255= FFH, 32= 20H etc. Parameters: Input : number to visualize in HEX Output : nothing **************************************************************************/ void vis_num(unsigned char t) { unsigned char h, l; cifre(t, &h, &l); // Splits in 2 nibble of t // high nibble and low nibble starti2c(); // Start sequence wri2c_byte(Wsaa1064); // Slave address rdi2c_bit(); // Check ACK on slave address+R wri2c_byte(Dig3); // First digit rdi2c_bit(); wri2c_byte(digit(h)); // Transforms into "7 segments" and send rdi2c_bit(); wri2c_byte(digit(l)); // Transforms into "7 segments" and send rdi2c_bit(); stopi2c(); // Stop sequence } void main(void) { unsigned char i, c; ritardo(2); iniser(19200); TI=0; RI=0; // Comment next lines if using serial line in polling (SIOTYPE=p or k) ES=1; // Enable interrupt serial port EA=1; // Enable all interrupts clrscr(); demo_init(); // Peripherals initialization i=0; puts("Press + to increment the output voltage level"); puts("Press - to decrement the output voltage level"); while(TRUE) // Infinite Loop { dac(i); // Set output voltage level vis_num(i); // Show value if(kbhit()) // If key pressed { c=getc(); switch(c) { case '+': i++; break; // Key + increment output case '-': i--; break; // Key - decrement output } } // end if(kbhit()) } // end while(TRUE) }