/* ********************************************************************** ** Program: ad11ch_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 program monitors one analogic channel out of eleven, managed by IC12 (TLC2543), visualization of the channel is in hexadecimal format, through T1 and T2 the channel to convert is selected, T1 increments while T2 decrements. The display shows first the channel being converted, then the 12 bits wide hexadecimal value of the channel converted: This demo allows to set which channel to convert through PC keyboard, and to read the combination on the 7 segments display of K51-AVR. 05.06.2000 by Adriano Pedrielli (Original version in BASCOM 8051) 03.10.2003 by Graziano Gaiba Translation in uC/51. */ #include #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 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 0, // writes DY1 off 0, // writes DY2 off 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 // Management of keys and buzzer bit unsigned char T1 @ 0x95; // P1.5 bit unsigned char T2 @ 0x94; // P1.4 bit unsigned char T3 @ 0x93; // P1.3 bit unsigned char BUZ @ 0xB5; // P3.5 // A/D converter TLC 2543 management bit unsigned char Cs @ 0x92; // P1.2 Chip Select for IC12 bit unsigned char Clk @ 0x91; // P1.1 Clock for IC12 bit unsigned char Din @ 0x90; // P1.0 Data In for IC12 bit unsigned char Dout @ 0xB7; // P3.7 Data Out for IC12 /********* 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 11059200 Hz 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 11059200 Hz. */ { unsigned int r,rit1ms; rit1ms=150; // 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); } /******************** A/D converter management ************************ This procedure performs serial communication with IC12 (TLC2543), on each Clock impulse it sends one bit and reads another one. Parameters: Input: adin as byte, byte to send to IC12 Ouput: 12 bit 0..FFF(0V..+Vref) conversione read ************************************************************************/ unsigned int ad12(unsigned char adin) { unsigned int adout; unsigned char i; adout = 0; // reset conversion read Cs = 0; // activate CS for(i=0; i<12; i++) // 12 times { Clk = 0; // set Clock to 0 if(adin & 0x80) // test bit7 of Adin { Din = 1; // set 1 signal to send to IC12 } else // or { Din = 0; // set to 0 signeal to IC12 } adin = (adin & 0x7F) << 1; // clear bit7 and shift left 1 position Clk = 1; // Set Clock signal to 1 if(Dout) // Test if data from IC12 is 1 { adout = adout | 1; // Set to 1 bit 0 of Adout } if(i!=11) // not in 12th cycle { adout<<=1; // shift left 1 position } } // end cycle Clk = 0; // set Clock to 0 Cs = 1; // diable CS return adout; } /********************** Analog conversion ****************************** Performs 12 bit conversion on each of the 11 channells of IC12 (TLC2543). Parameters: Input: ch as byte, channell to convert 0..10 Output: conversion read 12 bit 0..FFF(0V..+Vref) ************************************************************************/ unsigned int adc(unsigned char ch) // Gestione dell'A/D converter { if(ch>10) { ch=10; // At most channell 10 } ch=(ch >> 4) | 0x08; // Select 12 bit conversion ad12(ch); // Read previous conversion ritardo(1); // Delay at least 100 usec return ad12(ch); // Returns current conversion } // 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 number from 0 to 15 in 7 segments *********** Converts a number from 0 to 15 in 7 segments digits format. Parameters: Input: value from 0 to 15 Output: same value in 7 segments format. ************************************************************************/ unsigned char digit(unsigned char n) { if(n < 16) { return cifra_7seg[n]; // read value from table } else { return 0; // if value greater than 15,turn off display } } /******************************* Show HEX word ***************************** This procedure allows to display a word in hexadecimal. First two displays (DY1 and DY2) will show high byte, while 2 remaining will show low byte (DY3 and DY4). E.g.: 65535= FFFFH, 257= 101H etc. Parameters: Input: hexadecimal number to display Output: nothing **************************************************************************/ void vis_word(unsigned int t) { unsigned char h, l; // Decomposition in 2 nibbles of high part of t cifre(t>>8, &h, &l); 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(h)); // Writes in DY1 most significant nibble rdi2c_bit(); wri2c_byte(digit(l)); // Writes in DY2 next nibble rdi2c_bit(); // Decomposition in 2 nibbles of low part of t cifre(t & 0xff, &h, &l); wri2c_byte(digit(h)); // Writes in DY3 most significant nibble rdi2c_bit(); wri2c_byte(digit(l)); // Writes in DY4 next nibble rdi2c_bit(); stopi2c(); // Stop sequence } /*********************** Analog conversion ****************************** This procedure displays which channell is converted currently, it writes "C", "H", and channell number in hexadecimal. Parameters: Input: t, indicates channel converted 0..10 Output: nothing **************************************************************************/ void vis_ch(unsigned char t) { starti2c(); // Start sequence wri2c_byte(Wsaa1064); // Slave address rdi2c_bit(); // Controlla ACK su slave address+R wri2c_byte(Dig1); // First digit rdi2c_bit(); wri2c_byte(0); // Turn off DY1 rdi2c_bit(); wri2c_byte(0x39); // Writes "C" on DY2 rdi2c_bit(); wri2c_byte(0x76); // Writes "H" on DY3 rdi2c_bit(); wri2c_byte(digit(t)); // Transforms in "7 segments" and sends rdi2c_bit(); stopi2c(); // Stop sequence } // Activate buzzer for specified time, in milliseconds void buzzer(unsigned int t) { BUZ=0; ritardo(t); BUZ=1; } // Performs debouncing on T1 and returns its status: // 1 if pressed // 0 if not pressed unsigned char debounceT1(void) { unsigned char status; unsigned int steps; if(T1) // If T1 not pressed... { return 0; // ...return it is not pressed } else { status=1; // Indicates that it is pressed steps=20; // Check for 20 times while(status) { if(T1) // If T1 not pressed... { status=0; // ...exit loop } if(! steps--) // If steps controls made... { break; // ...exit } ritardo(5); // Delay between controls } return status; // Returns status of T1 } } // Performs debouncing on T2 and returns its status: // 1 if pressed // 0 if not pressed unsigned char debounceT2(void) { unsigned char status; unsigned int steps; if(T2) // If T2 not pressed... { return 0; // ...return it is not pressed } else { status=1; // Indicates that it is pressed steps=20; // Check for 20 times while(status) { if(T2) // If T2 not pressed... { status=0; // ...exit loop } if(! steps--) // If steps controls made... { break; // ...exit } ritardo(5); // Delay between controls } return status; // Restituisce lo stato di T2 } } // Performs debouncing on T3 and returns its status: // 1 if pressed // 0 if not pressed unsigned char debounceT3(void) { unsigned char status; unsigned int steps; if(T3) // If T3 not pressed... { return 0; // ...return it is not pressed } else { status=1; // Indicates that it is pressed steps=20; // Check for 20 times while(status) { if(T3) // If T3 not pressed... { status=0; // ...exit loop } if(! steps--) // If steps controls made... { break; // ...exit } ritardo(5); // Delay between controls } return status; // Restituisce lo stato di T3 } } // Performs the operations matched to the keys void gestioneTasti(unsigned char *c) { if(debounceT1()) // If T1 pressed { buzzer(50); // Makes a beep if(*c<10) // Increment channell number... { (*c)++; } else { *c=0; // ...or back to channell zero } } if(debounceT2()) // If T2 pressed { buzzer(50); // Makes a beep if(*c) // Decrement channell number... { (*c)--; } else { *c=10; // ...or back to channell zero 10 } } } 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 demo_init(); // Peripherals initialization c=0; while(TRUE) // Infinite Loop { for(i=0; i<10; i++) { vis_ch(c); // Show channell number gestioneTasti(&c); // Performs operations matched to keys ritardo(50); // Delay for visualization } // end for() for(i=0; i<35; i++) { vis_word(adc(c)); // Show conversion read from channell in c gestioneTasti(&c); // Performs operations matched to keys ritardo(50); // Delay for visualization } } // end while(TRUE) }