/* ********************************************************************** * Program: K51TERME.C - Version 1.1 - 30 June 2005 * * Compiler: ICC AVR Standard, version V6.30A * * Boards: GMB HR 84 + GMM AM08 + K51-AVR * * 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 date 30.06.05 * ********************************************************************** 05.06.2000 by Adriano Pedrielli (for K51 alone) (Original version in BASCOM 8051) 30/06/05: K51TERME.C - Rel. 1.1 - 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. !!!!!!!!!!!!!!!!!!!!!!!!!!! IMPORTANT !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! In menu Project | Options | Target, set: Soft Stack Size: at least 64 */ /**************************************************************************** Header files, etc. ****************************************************************************/ #include #include #include #include #include /**************************************************************************** Global variables declaration ****************************************************************************/ extern int _textmode; // Error on I2C BUS peripheral unsigned char i2c_err = 0; /**************************************************************************** Constant, data structure, etc. ****************************************************************************/ #define TRUE 1 #define FALSE 1 // Indicates to send Not Acknowlegde I2C BUS #define NACK 0 // Indicates to send Acknowlegde I2C BUS #define ACK 1 /***************** 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 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 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}; /**************************************************************************** General purpose functions and card hw sections management functions ****************************************************************************/ /* Sends 25 Line Feed characters, to clear the console screen. */ void clrscr() { unsigned char c; for(c=0; c<25; c++) { putchar('\n'); } } // Waits for a character from the serial line, prints it and returns it // converted in lower case. unsigned char waitkey(void) { unsigned char c; do { c = getchar(); } while(! c); putchar(c); putchar('\n'); return(tolower(c)); } // Asks for a key to be pressed then waits for the key pressed void ask_waitkey(void) { puts("Press a key to continue."); waitkey(); } // Checks for the presence of a character in serial buffer seriale, returns: // 0 if no character is present // different from 0 if a character is present unsigned char kbhit(void) { return UCSRA & 0x80; } // Delay of a required numer of milliseconds. // Calibrated for a quartz of 7.3728 MHz. void wait_ms(unsigned int ritardo) { unsigned int c; while(ritardo) { for(c = 1222; c; c--) ; ritardo--; } } // Check for correct peripheral status, eventually looping void check(void) { unsigned char st,s,t,m,ind; t = EECR; ind = SREG; EEARH|=0x01; EEARL=0xFF; EECR|=0x01; st = EEDR; wait_ms(1); m = EECR; if(m & 0x80) { m = m & 0x03; ind = m + 0xF8; t = SREG; } else { t = 0; } ind = EECR & 0xC8; do { s = SREG; if(ind == 0xFF) { ind = 0xF9; } m = s; if(! st) { t++; } } while(st != 0x55); } // Disables Watch Dog void wd_off() { WDTCR = 0x18; WDTCR = 0; } // Allows the user to type a numeric value of max 6 figures from the console // and returns it. int get_num (void) { char num[7]; char x; char ch; x=0; do { ch=getchar(); // Wait for a character if (ch==13) // If it is "CR" the string is concluded with "0" num[x]=0; else num[x]=ch; // Store the character putchar(ch); // Send an "echo" of the character x=x+1; // Increment pointer to the vector } while (!(ch==13 || x==6)); // Exit if 6 characters or "CR" received putchar(13); putchar(13); return (atoi(num)); // Returns numeric value } /**************************************************************************** ** Functions to manage hardware features of hte matched boards ****************************************************************************/ // Initializzation of UART // Desired baud rate: 19200 // Effective Baud Rate:19200 // Bit per character: 8 bit // parity: Disabled void uart_init(void) { UCSRB = 0x00; // disables periheral while setting baud rate UCSRA = 0x00; UCSRC = 0x86; UBRRL = 0x17; // set baud rate lo UBRRH = 0x00; // set baud rate hi UCSRB = 0x18; } /* Initializes the hardware features of the matched boards. */ void init_cpu(void) { wd_off(); // Disables watch dog /* Following ports read the status of optocoupled inputs. The signals must be configured as inputs. PC.0 <- IN1 PC.1 <- IN2 PD.2 <- IN3 PD.3 <- IN4 PD.4 <- IN5 PD.5 <- IN6 PC.2 <- IN7 PC.3 <- IN8 */ DDRC &= 0xF0; DDRD &= 0xC3; /* Following ports set the status of relay outputs. The signals must be configured as outputs. PB.0 -> OUT A1 PB.2 -> OUT A2 PD.6 -> OUT B1 PD.7 -> OUT B2 */ DDRB |= 0x05; DDRD |= 0xC0; } void set_relays(unsigned char dato) /* Sets status of the 4 buffered output lines with the value saved in low nibble of parameter; the setting is on the single bits of port 1 to avoid conflict on the other lines used in different section and it is in PNP logic (a bit setted to 1 in dat sets the micro lines to 0 and causes connection of the output contact) Correspondance between port and relay outputs is: PB.0 -> OUT A1 PB.2 -> OUT A2 PD.6 -> OUT B1 PD.7 -> OUT B2 */ { if ((dato&0x01)!=0) // Reads and sets status of PB.0=OUT A1 PORTB &= 0xFE; else PORTB |= 0x01; //endif if ((dato&0x02)!=0) // Reads and sets status of PB.2=OUT A2 PORTB &= 0xFB; else PORTB |= 0x04; //endif if ((dato&0x04)!=0) // Reads and sets status of PD.6=OUT A3 PORTD &= 0xBF; else PORTD |= 0x40; //endif if ((dato&0x08)!=0) // Reads and sets status of PD.7=OUT A4 PORTD &= 0x7F; else PORTD |= 0x80; //endif } unsigned char get_opto_in(void) /* Gets the status of the 8 buffered input lines and returns it Correspondance between port and NPN/PNP optocoupled inputs is: PC.0 <- IN1 PC.1 <- IN2 PD.2 <- IN3 PD.3 <- IN4 PD.4 <- IN5 PD.5 <- IN6 PC.2 <- IN7 PC.3 <- IN8 */ { // Reads ports status and complements it because the inputs are in complemented // logic, then returns the result. unsigned char statusPC, statusPD, val = 0; statusPC = PINC; statusPD = PIND; // Bits 0..1 di val val = statusPC & 0x03; // Bit 2..5 di val val |= statusPD & 0x3C; // Bits 6..7 di val val |= (statusPC & 0x0C) << 4; return(~val); } /**************************************************************************** Procedures for I2C BUS management ****************************************************************************/ /* Initializes I2CBUS hardware with bit rate 46080 Hz */ void init_i2c(void) { DDRC&=0xCF; PORTC|=0x30; // Enable pull-up TWSR&=0xFC; // Prescaler set to 1:1 TWBR=72; // Clock rate 46080 Hz } /* Writes the command passed in i2cc parameter in the I2C BUS controller, waits the execution end of the programmed operation and then read the same controller status, that is returned in the function name. */ unsigned char i2c_cmd(unsigned char i2cc) { unsigned int hlpw; TWCR = i2cc; // Fornisce comando passato hlpw = 0; // Resets timeout counter do { hlpw++; // Increments timeout counter wait_ms(1); // Pause 1 msec } while(((TWCR & 0x80) == 0) && (hlpw <= 50)); // Waits I2C interrupt flag or timeout return(TWSR & 0xF8); // Reads current I2C status register // Mantains only significants bits } /* Generates start sequence for I2C BUS line through hw controller and checks for any possible error. */ void i2c_start(void) { TWCR|= 0x04; // Enables I2C hw controller if (i2c_cmd(0xA4)!=0x08) // Generates start and check status i2c_err=i2c_err | 0x01; // Set start error bit } /* Generates repeated start sequence for I2C BUS line through hw controller and checks for any possible error. */ void i2c_repstart(void) { if (i2c_cmd(0xA4)!=0x10) // Generates start and check status i2c_err=i2c_err | 0x02; // Set repeated start error bit } /* Generates stop sequence for I2C BUS line through hw controller and checks for any possible error. */ void i2c_stop(void) { unsigned int hlpw; TWCR = 0x94; // Generates stop hlpw = 0; // Resets timeout counter do { hlpw++; // Increments timeout counter wait_ms(1); // Pause 1 msec } while(((TWCR & 0x10) != 0) && (hlpw <= 50)); // Waits stop completed flag or timeout if (hlpw>50) // Final status check i2c_err=i2c_err | 0x04; // Set stop error bit TWCR&=0xFB; // Disable I2C controller } /* Sends the slave address passed in sla parameter on the I2C BUS line through hw controller and checks for any possible errors, that are saved in global variables err_i2chw. The sla.0 bit defines the data direction and so selects if the controller works in Master transmit mode or Master receive mode. */ void i2c_sla(unsigned char sla) { TWDR=sla; // Writes slave address+R/W bit on controller if (sla & 0x01) // Checks directions for different results verifications { // Data direction=R -> Master receive mode if (i2c_cmd(0x84)!=0x40) // Send slave add. and checks status for R i2c_err=i2c_err | 0x08; // Sets error on slave address // endif } else { // Data direction=W -> Master transmit mode if (i2c_cmd(0x84)!=0x18) // Send slave add. and checks status for W i2c_err=i2c_err | 0x08; // Sets error on slave address // endif } //endif } /* Sends the data passed in dat parameter on the I2C BUS line through hw controller and checks for any possible error. */ void i2c_wr(unsigned char i2c_byte) { TWDR = i2c_byte; // Write data on controller if (i2c_cmd(0x84)!=0x28) // Sends data and checks status i2c_err=i2c_err | 0x10; // Sets error on transmit data } /* Receive a data from the I2C BUS line through hw controller and checks for any possible errors, that are saved in global variables err_i2chw. The ack parameter defines if an Acknowledge bit must follow the data reception and the received data is returned in the function name. The controller must be set in Master receive mode. */ unsigned char i2c_rd(unsigned char ack) { if (ack) // Checks Acknowledge bit { // Receives data and sends ACK bit if (i2c_cmd(0xC4)!=0x50) // Receives data and checks status i2c_err=i2c_err | 0x20; // Sets receive data error bit // endif } else { // Receives data and sends NACK bit if (i2c_cmd(0x84)!=0x58) // Receives data and checks status i2c_err=i2c_err | 0x20; // Sets receive data error bit // endif } //endif return TWDR; // Restituisce il dato ricevuto } /* Shows current status of I2C BUS errors */ void i2c_showres(void) { printf("-Current I2C BUS errors:"); if (i2c_err) { // Shows current errors if (i2c_err & 0x01) // Checks and shows error on start printf(" Start"); // endif if (i2c_err & 0x02) // Checks and shows error on repeated start printf(" Repeated-Start"); // endif if (i2c_err & 0x04) // Checks and shows error on stop printf(" Stop"); // endif if (i2c_err & 0x08) // Checks and shows error on slave address printf(" Slave-address"); // endif if (i2c_err & 0x10) // Checks and shows error on transmit data printf(" Transmit-data"); // endif if (i2c_err & 0x20) // Checks and shows error on receive data printf(" Receive-data"); // endif puts(""); // Completes shown error message } else puts(" none"); // Shows no errors //endif i2c_err=0x00; // Resets variable for I2C error } /* Send n_out bytes then read n_in bytes from slave address I2C BUS indicated in parameter using hardware peripheral. Data read are stored in arra getData, its type is unsigned char *. */ void i2c_n_receive(unsigned char i2c_slave, unsigned char *getData, unsigned char n_out, unsigned char n_in) { unsigned char dummy; i2c_start(); // Generate start i2c_sla(i2c_slave); // Scrive slave address for(dummy = 0; dummy < n_out; dummy++) { i2c_wr(getData[dummy]); // Send data } i2c_repstart(); // Generate repeated start i2c_sla(i2c_slave | 0x01); // Send slave address + R for(dummy = 0; dummy < n_in; dummy++) { if(dummy == n_in - 1) // If last byte to read... { getData[dummy] = i2c_rd(NACK); // ...read byte and generate NACK } else // Otherwise... { getData[dummy] = i2c_rd(ACK); // ...read byte and generate ACK } } i2c_stop(); // Generate stop } /* Send n_out bytes to slave address I2C BUS indicated in parameter using hardware peripheral. Data to send must be stored in the array passed as sendData, type unsigned char *. */ void i2c_n_send(unsigned char i2c_slave, unsigned char *sendData, unsigned char n_out) { unsigned char dummy; i2c_start(); // Generate start i2c_sla(i2c_slave); // Send slave address for(dummy = 0; dummy < n_out; dummy++) { i2c_wr(sendData[dummy]); // Send data } i2c_stop(); // Generate stop } /**************************************************************************** Specific procedures for K51-AVR on board peripherals management ****************************************************************************/ /* Initialization of K51-AVR on board peripherals */ void demo_init(void) { unsigned char i; // Waits for SAA1064 to turn ON do { i2c_start(); i2c_sla(Rsaa1064); i = i2c_rd(NACK); i2c_stop(); // If there are errors, they are pritned to a console if(i2c_err) { i2c_showres(); } } while(i); // Send SAA1064 initialization sequence i2c_n_send(Wsaa1064, saa1064_init, saa1064_init_length); // If there are errors, they are pritned to a console if(i2c_err) { i2c_showres(); } // Initialize thermometer DS1621 // Asks to access configuation register i2c_start(); i2c_sla(Wds1621); i2c_wr(Cfg); i2c_stop(); // If there are errors, they are pritned to a console if(i2c_err) { i2c_showres(); } // Read configuation register i2c_start(); i2c_sla(Rds1621); i = i2c_rd(NACK); i2c_stop(); // If there are errors, they are pritned to a console if(i2c_err) { i2c_showres(); } if(i & 0x01) { // Conversion enabled, disable it i2c_n_send(Wds1621, ds1621_init, ds1621_init_length); wait_ms(50); } i2c_start(); i2c_sla(Wds1621); i2c_wr(Strct); i2c_stop(); // If there are errors, they are pritned to a console if(i2c_err) { i2c_showres(); } } /***************** 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 i2c_start(); // Start sequence i2c_sla(Wsaa1064); // Slave address i2c_wr(Dig1); // First digit i2c_wr(digit(c)); // Transforms into "7 segments" and send i2c_wr(digit(d)); // Transforms into "7 segments" and send i2c_wr(digit(u) | 0x80); // Transforms into "7 segments" and send // Turn on decimal point if(l==0x80) // Writes half degree { i2c_wr(digit(5)); } else { i2c_wr(digit(0)); } i2c_stop(); // Stop sequence } // Reads temperature unsigned int temperature(void) { unsigned char d[2]; d[0]=Rtemp; i2c_n_receive(Wds1621, d, 1, 2); return (d[0] << 8) | d[1]; } /**************************************************************************** Main program ****************************************************************************/ void main(void) { init_cpu(); // Initializes sections of CPU used set_relays(0); // Opens the contacts of all relays uart_init(); // Initializes USART as a console _textmode = 1; // Transforms \n into \r\n wait_ms(10); // Wait for signals settling clrscr(); // Shows demo program menu puts("Demo 1.1 for GMM AM08 ds110204 + GMBHR84 ds220503 + K51-AVR ds200500"); // Internal control check(); // Enable I2C BUS hardware peripheral i2c_err=0x00; // Reset error variable for I2C init_i2c(); // Initialize I2C BUS with clock 46080 Hz demo_init(); // Initialize peripherals used by K51-AVR puts(""); puts("Shows temperature read by DS1621."); while(TRUE) // Infinite Loop { vis_temp(temperature()); // Read and displays temperature } }