/* ********************************************************************** ** Program: g51terme.c - Version : 1.4 - 23 June 2003 ** ** Compilatore : uC/51 Ver. 1.10.7 ** ** Scheda : K51-AVR through GMB HR84 and CAN GM1 or CAN GM2 ** ** Ditta: 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, DS1621, through mini-BLOCK module GMB HR84 and grifo(r) mini module. DS1621 is a programmable digital thermometer, whose resolution is half Celsius degreese, all the operations of programming and temperature acquisition are performed through synchronous serial interface I2C BUS. This demo shows the temperature acquired on the 7 segments display of K51-AVR. 05.06.2000 by Adriano Pedrielli (for K51 alone) (Original version in BASCOM 8051) 16.04.2003 by Graziano Gaiba (Original version in BASCOM 8051) Modified to drive the peripheral managed on K51-AVR throuth a GMB HR84 and a GMM 5115. 23.06.2003 by Graziano Gaiba Translation in uC/51. */ #include "canary.h" #include #include #define FALSE 0x00 // Boolean values #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 DS1621 ***********************/ #define Ds1621 0x4C // Slave address DS1621 #define Wds1621 0x98 // Slave address DS1621 in Write #define Rds1621 0x99 // Slave address DS1621 in Read /******************* Commands list for DS1621 ***********************/ #define Cfg 0xAC // R/W Reg. Config per DS1621 #define Rtemp 0xAA // Leggi temperatura 2 bytes #define Strct 0xEE // Start temperature conversion #define Stpct 0x22 // Stop temperature conversion // 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 0, // writes DY1 off 0, // writes DY2 off 0, // writes DY3 off 0 // writes DY4 off }; #define ds1621_init_length 0x03 // Inizialization sequence length const unsigned char ds1621_init[]={ Wds1621, // Slave address Cfg, // Points to Configuration register 0x0A // Writes into Configuration register }; // Codes to convert a figure from 0 to 9 in 7 segments coding const unsigned char cifra_7seg[]={0x3F,0x06,0x5B,0x4F,0x66, 0x6D,0x7D,0x07,0x7F,0x6F}; // I2C BUS management globals bit unsigned char SDA @ 0xA0; // Pin SDA=P2.1 bit unsigned char SCL @ 0xA1; // Pin SCL=P2.0 /********* 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*14745600)/(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 14.7456 MHz. */ { unsigned int r,rit1ms; rit1ms=100; // Sperimental value for delay of 1 msec. with 80c32 do { for (r=0 ; r0); } void init_cpu(void) /* Performs initialization of serial line, wait states, etc... */ { ES=1; // Enable serial port interrupt EA=1; // Enable interrupt CKCON=0x00; // Set X1 clock mode = standard mode AUXR=0x0C; // Select ERAM for external data area EECON=0x00; // Disabiles EEPROM of micro } 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 sequence i2c_invia(Wsaa1064, saa1064_init, saa1064_init_length); // Initializes thermometer DS1621 // Asks access to configuration register starti2c(); wri2c_byte(Wds1621); rdi2c_bit(); wri2c_byte(Cfg); rdi2c_bit(); stopi2c(); // Reads configuration register starti2c(); wri2c_byte(Rds1621 | 0x01); rdi2c_bit(); i = rdi2c_byte(); wri2c_byte(1); // Not Acknowledge stopi2c(); if(i & 0x01) // If value in AND with 1 is still 1 { // Conversion is OFF, activate it i2c_invia(Wsaa1064, ds1621_init, ds1621_init_length); ritardo(50); } else { starti2c(); wri2c_byte(Wds1621); rdi2c_bit(); wri2c_byte(Strct); rdi2c_bit(); stopi2c(); } } /***************** Converte 1 byte in two "temperature" figures ************* This procedure converts 1 byte from 0 to 255 in a temperature, that is a value from 0 to 125 means positive centigrad degreeses (+0..+125), while a value from 255 to 201 means negative centigrad degreeses (-0..-55), bit 7 is the sign bit, negative degreeses are obtained complementing. E.g.: Not 255=0, Not 201=54 Parameters: Input : value from 0 to 255 Uscita : hundreds, decines and units of the temperature. **************************************************************************/ void cifre(unsigned char v, unsigned char *c1, unsigned char *c2, unsigned char *c3) { unsigned char c, d, u; if(v > 127) // negative temperature { c = 10; // activate minus sign v=~v; // complement value } else { if(v > 99) // positive temperature, if over 99 { c = 1; // activate number 1 of hundreds v-=100; // subract 100 } else { c = 11; // less than 99, turn off hundreds } } if(v > 9) // over 9 { d = v / 10; // figure of decines u = v - (d * 10); // figure of units } else { if(c==11) // less than 9 and hundreds OFF { d = 11; // decines OFF } else { if(c==10) // less than 9 and negative temperature { d = 11; // decines OFF } else { d = 0; // less than 9 and hundreds ON } // display a zero } u = v; // save units } *c1=c; *c2=d; *c3=u; } /***************** Converts a number from 0 to 9 in 7 segments *********** Converts a number from 0 to 9 into 7 segments format, if its value is greater than or equal to 11, display is OFF, if equal to 10 a negative sign is displayed. Parametri: Input : value from 0 to 9 Output : value in 7 segments format. ************************************************************************/ unsigned char digit(unsigned char n) { if(n < 10) { return cifra_7seg[n]; // reads value from table } else { if(n > 10) { return 0; // If value over 10, display OFF } else { return 0x40; // If value is 10, display "-" } } } void vis_temp(unsigned int t) { unsigned char h, l; unsigned char c, d, u; h=t>>8; // Degreeses and sign l=t & 0x00ff; // Half degree cifre(h, &c, &d, &u); // Split into three figures: // hundreds, decines and units with sign starti2c(); // Start sequence wri2c_byte(Wsaa1064); // Slave address rdi2c_bit(); // Check ACK on slave address+R wri2c_byte(Dig1); // First digit rdi2c_bit(); wri2c_byte(digit(c)); // Transforms into "7 segments" and send rdi2c_bit(); wri2c_byte(digit(d)); // Transforms into "7 segments" and send rdi2c_bit(); wri2c_byte(digit(u) | 0x80); // Transforms into "7 segments" and send rdi2c_bit(); // Turn on decimal point if(l==0x80) // Writes half degree { wri2c_byte(digit(5)); } else { wri2c_byte(digit(0)); } rdi2c_bit(); stopi2c(); // Stop sequence } // Reads temperature unsigned int temperatura(void) { unsigned char d[2]; unsigned char h, l; d[0]=Rtemp; i2c_ricevi(Wds1621, d, 1, 2); return (d[0] << 8) | d[1]; } void main(void) { ritardo(2); init_cpu(); iniser(19200); clrscr(); puts("This demo has been made to run only on a GMM 5115."); puts("Proceed only if you have the correct Mini Module!"); puts("Press a key if you want to continue..."); getc(); // Attende un tasto puts("Running."); demo_init(); // Peripherals initialization while(TRUE) // Infinite Loop { vis_temp(temperatura()); // Read and displays temperature } }